In this section, we describe functions related to general number fields. Functions related to quadratic number fields are found in Section se:arithmetic (Arithmetic functions).
Let K = ℚ[X] / (T) a number field, ℤK its ring of integers, T ∈ ℤ[X] is monic. Three basic number field structures can be attached to K in GP:
* nf denotes a number field, i.e. a data structure output by
nfinit
. This contains the basic arithmetic data attached to the
number field: signature, maximal order (given by a basis nf.zk
),
discriminant, defining polynomial T, etc.
* bnf denotes a "Buchmann's number field", i.e. a
data structure output by bnfinit
. This contains
nf and the deeper invariants of the field: units U(K), class group
Cl(K), as well as technical data required to solve the two attached
discrete logarithm problems.
* bnr denotes a "ray number field", i.e. a data structure
output by bnrinit
, corresponding to the ray class group structure of
the field, for some modulus f. It contains a bnf, the modulus
f, the ray class group Clf(K) and data attached to
the discrete logarithm problem therein.
An algebraic number belonging to K = ℚ[X]/(T) is given as
* a t_INT
, t_FRAC
or t_POL
(implicitly modulo T), or
* a t_POLMOD
(modulo T), or
* a t_COL
v
of dimension N = [K:ℚ], representing
the element in terms of the computed integral basis, as
sum(i = 1, N, v[i] * nf.zk[i])
. Note that a t_VEC
will not be recognized.
An ideal is given in any of the following ways:
* an algebraic number in one of the above forms, defining a principal ideal.
* a prime ideal, i.e. a 5-component vector in the format output by
idealprimedec
or idealfactor
.
* a t_MAT
, square and in Hermite Normal Form (or at least
upper triangular with nonnegative coefficients), whose columns represent a
ℤ-basis of the ideal.
One may use idealhnf
to convert any ideal to the last (preferred) format.
* an extended ideal is a 2-component
vector [I, t], where I is an ideal as above and t is an algebraic
number, representing the ideal (t)I. This is useful whenever idealred
is involved, implicitly working in the ideal class group, while keeping track
of principal ideals. The following multiplicative ideal operations
update the principal part: idealmul
, idealinv
,
idealsqr
, idealpow
and idealred
; e.g. using idealmul
on [I,t], [J,u], we obtain [IJ, tu]. In all other
functions, the extended part is silently discarded, e.g. using
idealadd
with the above input produces I+J.
The "principal part" t in an extended ideal may be
represented in any of the above forms, and also as a factorization
matrix (in terms of number field elements, not ideals!), possibly the empty
factorization matrix factor(1)
representing 1; the empty matrix
[;]
is also accepted as a synonym for 1. When t is such a
factorization matrix, elements stay in
factored form, or famat for factorization matrix, which
is a convenient way to avoid coefficient explosion. To recover the
conventional expanded form, try nffactorback
; but many functions
already accept famats as input, for instance ideallog
, so
expanding huge elements should never be necessary.
A finite abelian group G in user-readable format is given by its Smith
Normal Form as a pair [h,d] or triple [h,d,g].
Here h is the cardinality of G, (di) is the vector of elementary
divisors, and (gi) is a vector of generators. In short,
G = ⨁ i ≤ n (ℤ/diℤ) gi, with
dn | ... | d2 | d1
and ∏i di = h. This information can also be retrieved as
G.no
, G.cyc
and G.gen
.
* a character on the abelian group ⨁ (ℤ/djℤ) gj is given by a row vector χ = [a1,...,an] such that χ(∏j gjnj) = exp(2π i∑j aj nj / dj).
* given such a structure, a subgroup H is input as a square matrix in HNF, whose columns express generators of H on the given generators gi. Note that the determinant of that matrix is equal to the index (G:H).
We now have a look at data structures attached to relative extensions of number fields L/K, and to projective ℤK-modules. When defining a relative extension L/K, the nf attached to the base field K must be defined by a variable having a lower priority (see Section se:priority) than the variable defining the extension. For example, you may use the variable name y to define the base field K, and x to define the relative extension L/K.
Basic definitions.
* rnf denotes a relative number field, i.e. a data structure
output by rnfinit
, attached to the extension L/K. The nf
attached to be base field K is rnf.nf
.
* A relative matrix is an m x n matrix whose entries are elements of K, in any form. Its m columns Aj represent elements in Kn.
* An ideal list is a row vector of fractional ideals of the number field nf.
* A pseudo-matrix is a 2-component row vector (A,I) where A is a relative m x n matrix and I an ideal list of length n. If I = {𝔞1,..., 𝔞n} and the columns of A are (A1,..., An), this data defines the torsion-free (projective) ℤK-module 𝔞1 A1⨁ 𝔞n An.
* An integral pseudo-matrix is a 3-component row vector (A,I,J) where A = (ai,j) is an m x n relative matrix and I = (𝔟1,..., 𝔟m), J = (𝔞1,..., 𝔞n) are ideal lists, such that ai,j ∈ 𝔟i 𝔞j-1 for all i,j. This data defines two abstract projective ℤK-modules N = 𝔞1ω1⨁ ...⨁ 𝔞nωn in Kn, P = 𝔟1η1⨁ ...⨁ 𝔟mηm in Km, and a ℤK-linear map f:N → P given by f(∑j αjωj) = ∑i (ai,jαj) ηi. This data defines the ℤK-module M = P/f(N).
* Any projective ℤK-moduleprojective module M of finite type in Km can be given by a pseudo matrix (A,I).
* An arbitrary ℤK module of finite type in Km, with nontrivial torsion, is given by an integral pseudo-matrix (A,I,J)
Algebraic numbers in relative extension.
We are given a number field K = nfinit
(T), attached to K = ℚ[Y]/(T),
T ∈ ℚ[Y], and a relative extension L = rnfinit
(K, P), attached
to L = K[X]/(P), P ∈ K[X].
In all contexts (except rnfeltabstorel
and rnfeltdown
, see below), an
algebraic number is given as
* a t_INT
, t_FRAC
or t_POL
in ℚ[Y] (implicitly modulo T)
or a t_POL
in K[X] (implicitly modulo P),
* a t_POLMOD
(modulo T or P), or
* a t_COL
v
of dimension m = [K:ℚ], representing
the element in terms of the integral basis K.zk
;
* if an absolute nf
structure Labs
was attached to L, via
Labs = nfinit
(L), then we can also use a t_COL
v
of
dimension [L:ℚ], representing the element in terms of the computed integral
basis Labs.zk
. Be careful that in the degenerate case
L = K, then the previous interpretation (with respect to K.zk
)
takes precedence. This is no concern when K = ℚ or if P = X - Y
(because in that case the primitive
polynomial Labs.pol
defining L of ℚ is nf.pol
and the
computation of nf.zk
is deterministic); but in other cases, the
integer bases attached to K and Labs
may differ.
Special case: rnfeltabstorel
and rnfeltdown
.
These two functions assume
that elements are given in absolute representation (with respect to
Labs.zk
or modulo Labs.pol
and converts them to relative
representation modulo L.pol
. In these two functions (only), a t_POL
in
X is implicitly understood modulo Labs.pol
and a t_COL
of length [L:ℚ] refers to the integral basis Labs.zk
in all cases,
including L = K.
Pseudo-bases, determinant.
* The pair (A,I) is a pseudo-basis of the module it generates if the 𝔞j are nonzero, and the Aj are K-linearly independent. We call n the size of the pseudo-basis. If A is a relative matrix, the latter condition means it is square with nonzero determinant; we say that it is in Hermite Normal Form (HNF) if it is upper triangular and all the elements of the diagonal are equal to 1.
* For instance, the relative integer basis rnf.zk
is a pseudo-basis
(A,I) of ℤL, where A = rnf.zk[1]
is a vector of elements of L,
which are K-linearly independent. Most rnf routines return and handle
ℤK-modules contained in L (e.g. ℤL-ideals) via a pseudo-basis
(A',I'), where A' is a relative matrix representing a vector of elements of
L in terms of the fixed basis rnf.zk[1]
* The determinant of a pseudo-basis (A,I) is the ideal equal to the product of the determinant of A by all the ideals of I. The determinant of a pseudo-matrix is the determinant of any pseudo-basis of the module it generates.
A modulus, in the sense of class field theory, is a divisor supported
on the real and finite places of K. In PARI terms, this means either an
ordinary ideal I as above (no Archimedean component), or a pair [I,a],
where a is a vector with r1 {0,1}-components, corresponding to the
infinite part of the divisor. More precisely, the i-th component of a
corresponds to the real embedding attached to the i-th real root of
K.roots
. (That ordering is not canonical, but well defined once a
defining polynomial for K is chosen.) For instance, [1, [1,1]]
is a
modulus for a real quadratic field, allowing ramification at any of the two
places at infinity, and nowhere else.
A bid or "big ideal" is a structure output by idealstar
needed to compute in (ℤK/I)*, where I is a modulus in the above sense.
It is a finite abelian group as described above, supplemented by
technical data needed to solve discrete log problems.
Finally we explain how to input ray number fields (or bnr), using class field theory. These are defined by a triple A, B, C, where the defining set [A,B,C] can have any of the following forms: [bnr], [bnr,subgroup], [bnr,character], [bnf,mod], [bnf,mod,subgroup]. The last two forms are kept for backward compatibility, but no longer serve any real purpose (see example below); no newly written function will accept them.
* bnf is as output by bnfinit
, where units are mandatory
unless the modulus is trivial; bnr is as output by bnrinit
. This
is the ground field K.
* mod is a modulus 𝔣, as described above.
* subgroup a subgroup of the ray class group modulo 𝔣 of
K. As described above, this is input as a square matrix expressing
generators of a subgroup of the ray class group bnr.clgp
on the
given generators. We also allow a t_INT
n for n.Clf.
* character is a character χ of the ray class group modulo 𝔣, representing the subgroup Ker χ.
The corresponding bnr is the subfield of the ray class field of K modulo 𝔣, fixed by the given subgroup.
? K = bnfinit(y^2+1); ? bnr = bnrinit(K, 13) ? %.clgp %3 = [36, [12, 3]] ? bnrdisc(bnr); \\ discriminant of the full ray class field ? bnrdisc(bnr, [3,1;0,1]); \\ discriminant of cyclic cubic extension of K ? bnrconductor(bnr, [3,1]); \\ conductor of chi: g1->zeta_12^3, g2->zeta3
We could have written directly
? bnrdisc(K, 13); ? bnrdisc(K, 13, [3,1;0,1]);
avoiding one bnrinit
, but this would actually be slower since the
bnrinit
is called internally anyway. And now twice!
All the functions which are specific to relative extensions, number fields,
Buchmann's number fields, Buchmann's number rays, share the prefix rnf
,
nf
, bnf
, bnr
respectively. They take as first argument a
number field of that precise type, respectively output by rnfinit
,
nfinit
, bnfinit
, and bnrinit
.
However, and even though it may not be specified in the descriptions of the
functions below, it is permissible, if the function expects a nf, to
use a bnf instead, which contains much more information. On the other
hand, if the function requires a bnf
, it will not launch
bnfinit
for you, which is a costly operation. Instead, it will give you
a specific error message. In short, the types
nf
≤ bnf
≤ bnr
are ordered, each function requires a minimal type to work properly, but you
may always substitute a larger type.
The data types corresponding to the structures described above are rather complicated. Thus, as we already have seen it with elliptic curves, GP provides "member functions" to retrieve data from these structures (once they have been initialized of course). The relevant types of number fields are indicated between parentheses:
bid
(bnr ) : bid ideal structure.
bnf
(bnr, bnf ) : Buchmann's number field.
clgp
(bnr, bnf ) : classgroup. This one admits the
following three subclasses:
cyc
: cyclic decomposition
(SNF).
gen
:
generators.
no
: number of elements.
diff
(bnr, bnf, nf ) : the different ideal.
codiff
(bnr, bnf, nf ) : the codifferent
(inverse of the different in the ideal group).
disc
(bnr, bnf, nf ) : discriminant.
fu
( bnf ) : fundamental units.
index
(bnr, bnf, nf ) :
index of the power order in the ring of integers.
mod
(bnr ) : modulus.
nf
(bnr, bnf, nf ) : number field.
pol
(bnr, bnf, nf ) : defining polynomial.
r1
(bnr, bnf, nf ) : the number
of real embeddings.
r2
(bnr, bnf, nf ) : the number
of pairs of complex embeddings.
reg
( bnf ) : regulator.
roots
(bnr, bnf, nf ) : roots of the
polynomial generating the field.
sign
(bnr, bnf, nf ) : signature [r1,r2].
t2
(bnr, bnf, nf ) : the T2 matrix (see
nfinit
).
tu
( bnf ) : a generator for the torsion
units.
zk
(bnr, bnf, nf ) : integral basis, i.e. a
ℤ-basis of the maximal order.
zkst
(bnr ) : structure of (ℤK/m)*.
The member functions .codiff
, .t2
and .zk
perform a
computation and are relatively expensive in large degree: move them out of
tight loops and store them in variables.
For instance, assume that bnf = bnfinit
(pol), for some
polynomial. Then bnf.clgp
retrieves the class group, and
bnf.clgp.no
the class number. If we had set bnf =
nfinit
(pol), both would have output an error message. All these
functions are completely recursive, thus for instance
bnr.bnf.nf.zk
will yield the maximal order of bnr, which
you could get directly with a simple bnr.zk
.
Some of the functions starting with bnf
are implementations of the
sub-exponential algorithms for finding class and unit groups under GRH,
due to Hafner-McCurley, Buchmann and Cohen-Diaz-Olivier. The general
call to the functions concerning class groups of general number fields
(i.e. excluding quadclassunit
) involves a polynomial P and a
technical vector
tech = [c1, c2, nrpid ],
where the parameters are to be understood as follows:
P is the defining polynomial for the number field, which must be in
ℤ[X], irreducible and monic. In fact, if you supply a nonmonic polynomial
at this point, gp
issues a warning, then transforms your
polynomial so that it becomes monic. The nfinit
routine
will return a different result in this case: instead of res
, you get a
vector [res,Mod(a,Q)]
, where Mod(a,Q) = Mod(X,P)
gives the change
of variables. In all other routines, the variable change is simply lost.
The tech interface is obsolete and you should not tamper with these parameters. Indeed, from version 2.4.0 on,
* the results are always rigorous under GRH (before that version, they relied on a heuristic strengthening, hence the need for overrides).
* the influence of these parameters on execution time and stack size is
marginal. They can be useful to fine-tune and experiment with the
bnfinit
code, but you will be better off modifying all tuning
parameters in the C code (there are many more than just those three).
We nevertheless describe it for completeness.
The numbers c1 ≤ c2 are nonnegative real numbers. By default they are chosen so that the result is correct under GRH. For i = 1,2, let Bi = ci(log |dK|)2, and denote by S(B) the set of maximal ideals of K whose norm is less than B. We want S(B1) to generate Cl(K) and hope that S(B2) can be proven to generate Cl(K).
More precisely, S(B1) is a factorbase used to compute a tentative
Cl(K) by generators and relations. We then check explicitly, using
essentially bnfisprincipal
, that the elements of S(B2) belong to the
span of S(B1). Under the assumption that S(B2) generates Cl(K), we
are done. User-supplied ci are only used to compute initial guesses for
the bounds Bi, and the algorithm increases them until one can prove
under GRH that S(B2) generates Cl(K). A uniform result of Grenié
and Molteni says
that c2 = 4 is always suitable, but this bound is very pessimistic and a
direct algorithm due to Belabas-Diaz-Friedman, improved by Grenié and
Molteni, is used to check the condition, assuming GRH. The default values
are c1 = c2 = 0. When c1 is equal to 0 the algorithm takes it
equal to c2.
nrpid is the maximal number of small norm relations attached to each ideal in the factor base. Set it to 0 to disable the search for small norm relations. Otherwise, reasonable values are between 4 and 20. The default is 4.
Warning. Make sure you understand the above! By default, most of
the bnf
routines depend on the correctness of the GRH. In particular,
any of the class number, class group structure, class group generators,
regulator and fundamental units may be wrong, independently of each other.
Any result computed from such a bnf
may be wrong. The only guarantee is
that the units given generate a subgroup of finite index in the full unit
group. You must use bnfcertify
to certify the computations
unconditionally.
Remarks.
You do not need to supply the technical parameters (under the library you
still need to send at least an empty vector, coded as NULL
). However,
should you choose to set some of them, they must be given in the
requested order. For example, if you want to specify a given value of
nrpid, you must give some values as well for c1 and c2,
and provide a vector [c1,c2,nrpid].
Note also that you can use an nf instead of P, which avoids recomputing the integral basis and analogous quantities.
Hecke Grossencharacters are continuous characters of the id\`ele class group; they generalize classical Hecke characters on ray class groups obtained through the bnr structure.
Let K be a number field, \A× its group of id\`eles. Every Grossencharacter
χ : \A×/K× → ℂ×
can be uniquely written χ = χ0 |.|s for some s ∈ ℂ and some character χ0 of the compact group \A×/(K×.ℝ > 0), where |a |= ∏v |av|v is the id\`ele norm.
Let 𝔪 be a modulus (an integral ideal and a finite set of real places). Let U(𝔪) be the subgroup of id\`eles congruent to 1 modulo 𝔪 (units outside 𝔪, positive at real places in 𝔪). The Hecke Grossencharacters defined modulo 𝔪 are the characters of the id\`ele class group
CK(𝔪) = \A×/(K×.U(𝔪)),
that is, combinations of an archimedean character χ oo on the connected component K oo x o and a ray class group character χf satisfying a compatibility condition χ oo (a)χf(a) = 1 for all units a congruent to 1 modulo 𝔪.
gchar * gc denotes a structure allowing to compute with Hecke Grossencharacters.
* gcharinit(bnf,mod)
initializes the structure gc.
The underlying number field and modulus can be accessed using
gc.bnf
and gc.mod
.
* gc.cyc
describes the finite abelian group structure of
gc, the torsion part corresponding to finite order ray class
characters, the exact zeros corresponding to a lattice of infinite order
Grossencharacters, and the approximate zero being a placeholder for the
complex powers of the id\`ele norm.
* A Hecke character of modulus 𝔪 is described as a t_COL
of
coordinates corresponding to gc.cyc
: all the coordinates are
integers except the last one, which can be an arbitrary complex number, or
omitted instead of 0.
* Hecke Grossencharacters have L-functions and can be given to all
lfun
functions as a 2 components vector [gc,chi]
, see
also Section se:lfungchar.
bnf being as output by
bnfinit
, checks whether the result is correct, i.e. whether it is
possible to remove the assumption of the Generalized Riemann
Hypothesis. It is correct if and only if the answer is 1. If it is
incorrect, the program may output some error message, or loop indefinitely.
You can check its progress by increasing the debug level. The bnf
structure must contain the fundamental units:
? K = bnfinit(x^3+2^2^3+1); bnfcertify(K) *** at top-level: K=bnfinit(x^3+2^2^3+1);bnfcertify(K) *** ^ — — — — - *** bnfcertify: precision too low in makeunits [use bnfinit(,1)]. ? K = bnfinit(x^3+2^2^3+1, 1); \\ include units ? bnfcertify(K) %3 = 1
If flag is present, only certify that the class group is a quotient of the one computed in bnf (much simpler in general); likewise, the computed units may form a subgroup of the full unit group. In this variant, the units are no longer needed:
? K = bnfinit(x^3+2^2^3+1); bnfcertify(K, 1) %4 = 1
The library syntax is long bnfcertify0(GEN bnf, long flag)
.
Also available is GEN bnfcertify(GEN bnf)
(flag = 0).
If m is a module as output in the
first component of an extension given by bnrdisclist
, outputs the
true module.
? K = bnfinit(x^2+23); L = bnrdisclist(K, 10); s = L[2] %1 = [[[Vecsmall([8]), Vecsmall([1])], [[0, 0, 0]]], [[Vecsmall([9]), Vecsmall([1])], [[0, 0, 0]]]] ? bnfdecodemodule(K, s[1][1]) %2 = [2 0] [0 1] ? bnfdecodemodule(K,s[2][1]) %3 = [2 1] [0 1]
The library syntax is GEN decodemodule(GEN nf, GEN m)
.
Initializes a
bnf
structure. Used in programs such as bnfisprincipal
,
bnfisunit
or bnfnarrow
. By default, the results are conditional
on the GRH, see se:GRHbnf. The result is a
10-component vector bnf.
This implements Buchmann's sub-exponential algorithm for computing the class group, the regulator and a system of fundamental units of the general algebraic number field K defined by the irreducible polynomial P with integer coefficients. The meaning of flag is as follows:
* flag = 0 (default). This is the historical behavior, kept for
compatibility reasons and speed. It has severe drawbacks but is likely to be
a little faster than the alternative, twice faster say, so only use it if
speed is paramount, you obtain a useful speed gain for the fields
under consideration, and you are only interested in the field invariants
such as the classgroup structure or its regulator. The computations involve
exact algebraic numbers which are replaced by floating point embeddings for
the sake of speed. If the precision is insufficient, gp
may not be able
to compute fundamental units, nor to solve some discrete logarithm problems.
It may be possible to increase the precision of the bnf
structure using nfnewprec
but this may fail, in particular when
fundamental units are large. In short, the resulting bnf
structure is correct and contains useful information but later
function calls to bnfisprincpal
or bnrclassfield
may fail.
When flag = 1, we keep an exact algebraic version of all floating point data
and this allows to guarantee that functions using the structure will always
succeed, as well as to compute the fundamental units exactly. The units are
computed in compact form, as a product of small S-units, possibly with
huge exponents. This flag also allows bnfisprincipal
to compute
generators of principal ideals in factored form as well. Be warned that
expanding such products explicitly can take a very long time, but they can
easily be mapped to floating point or ℓ-adic embeddings of bounded
accuracy, or to K*/(K*)ℓ, and this is enough for applications. In
short, this flag should be used by default, unless you have a very good
reason for it, for instance building massive tables of class numbers, and
you do not care about units or the effect large units would have on your
computation.
tech is a technical vector (empty by default, see se:GRHbnf). Careful use of this parameter may speed up your computations, but it is mostly obsolete and you should leave it alone.
The components of a bnf are technical. In fact: never access a component directly, always use a proper member function. However, for the sake of completeness and internal documentation, their description is as follows. We use the notations explained in the book by H. Cohen, A Course in Computational Algebraic Number Theory, Graduate Texts in Maths 138, Springer-Verlag, 1993, Section 6.5, and subsection 6.5.5 in particular.
bnf[1] contains the matrix W, i.e. the matrix in Hermite normal form giving relations for the class group on prime ideal generators (𝔭i)1 ≤ i ≤ r.
bnf[2] contains the matrix B, i.e. the matrix containing the expressions of the prime ideal factorbase in terms of the 𝔭i. It is an r x c matrix.
bnf[3] contains the complex logarithmic embeddings of the system of fundamental units which has been found. It is an (r1+r2) x (r1+r2-1) matrix.
bnf[4] contains the matrix M"C of Archimedean components of the relations of the matrix (W|B).
bnf[5] contains the prime factor base, i.e. the list of prime ideals used in finding the relations.
bnf[6] contains a dummy 0.
bnf[7] or bnf.nf
is equal to the number field data
nf as would be given by nfinit
.
bnf[8] is a vector containing the classgroup bnf.clgp
as a finite abelian group, the regulator bnf.reg
,
the number of roots of unity and a generator bnf.tu
, the
fundamental units in expanded form bnf.fu
. If the
fundamental units were omitted in the bnf, bnf.fu
returns
the sentinel value 0. If flag = 1, this vector contain also algebraic
data corresponding to the fundamental units and to the discrete logarithm
problem (see bnfisprincipal
). In particular, if flag = 1 we may
only know the units in factored form: the first call to
bnf.fu
expands them, which may be very costly, then caches the
result.
bnf[9] is a vector used in bnfisprincipal
only
and obtained as follows. Let D = U W V obtained by applying the
Smith normal form algorithm to the matrix W ( = bnf[1]) and
let Ur be the reduction of U modulo D. The first elements of the
factorbase are given (in terms of bnf.gen
) by the columns of Ur,
with Archimedean component ga; let also GDa be the Archimedean
components of the generators of the (principal) ideals defined by the
bnf.gen[i]^bnf.cyc[i]
. Then bnf[9] = [Ur, ga, GDa],
followed by technical exact components which allow to recompute ga and
GDa to higher accuracy.
bnf[10] is by default unused and set equal to 0. This field is used
to store further information about the field as it becomes available, which
is rarely needed, hence would be too expensive to compute during the initial
bnfinit
call. For instance, the generators of the principal ideals
bnf.gen[i]^bnf.cyc[i]
(during a call to bnrisprincipal
), or
those corresponding to the relations in W and B (when the bnf
internal precision needs to be increased).
The library syntax is GEN bnfinit0(GEN P, long flag, GEN tech = NULL, long prec)
.
Also available is GEN Buchall(GEN P, long flag, long prec)
,
corresponding to tech = NULL
, where
flag is either 0 (default) or nf_FORCE
(include all data in
algebraic form). The function
GEN Buchall_param(GEN P, double c1, double c2, long nrpid, long flag, long prec)
gives direct access to the technical parameters.
Computes a complete system of
solutions (modulo units of positive norm) of the absolute norm equation
Norm(a) = x,
where a is an integer in bnf. If bnf has not been certified,
the correctness of the result depends on the validity of GRH.
If (optional) flag is set, allow returning solutions in factored form, which
helps a lot when the fundamental units are large (equivalently, when bnf.reg
is large); having an exact algebraic bnf from bnfinit(,1)
is
necessary in this case, else setting the flag will mostly be a no-op.
? bnf = bnfinit(x^4-2, 1); ? bnfisintnorm(bnf,7) %2 = [-x^2 + x - 1, x^2 + x + 1] ? bnfisintnorm(bnf,-7) %3 = [-x^3 - 1, x^3 + 2*x^2 + 2*x + 1] ? bnf = bnfinit(x^2-2305843005992468481, 1); ? bnfisintnorm(bnf, 2305843008139952128) \\ stack overflow with 100GB parisize ? bnf.reg \\ fundamental unit is huge %6 = 14054016.227457155120413774802385952043 ? v = bnfisintnorm(bnf, 2305843008139952128, 1); #v %7 = 31 \\ succeeds instantly ? s = v[1]; [type(s), matsize(s)] %8 = ["t_MAT", [165, 2]] \\ solution 1 is a product of 165 factors ? exponent(s[,2]) %9 = 105
The exponents have 105 bits, so there is indeed little hope of writing down the solutions in expanded form.
See also bnfisnorm
.
The library syntax is GEN bnfisintnorm0(GEN bnf, GEN x, long flag)
.
The function GEN bnfisintnormabs0(GEN bnf, GEN a, long flag)
,
where bnf
is a true bnf structure,
returns a complete system of solutions modulo units of the absolute norm
equation |Norm(x) |= |a|. As fast as bnfisintnorm
, but solves
the two equations Norm(x) = ± a simultaneously. The functions
GEN bnfisintnormabs(GEN bnf, GEN a)
,
GEN bnfisintnorm(GEN bnf, GEN a)
correspond to flag = 0.
Tries to tell whether the rational number x is the norm of some element y in bnf. Returns a vector [a,b] where x = Norm(a)*b. Looks for a solution which is an S-unit, with S a certain set of prime ideals containing (among others) all primes dividing x. If bnf is known to be Galois, you may set flag = 0 (in this case, x is a norm iff b = 1). If flag is nonzero the program adds to S the following prime ideals, depending on the sign of flag. If flag > 0, the ideals of norm less than flag. And if flag < 0 the ideals dividing flag.
Assuming GRH, the answer is guaranteed (i.e. x is a norm iff b = 1), if S contains all primes less than 4log(disc(Bnf))2, where Bnf is the Galois closure of bnf.
See also bnfisintnorm
.
The library syntax is GEN bnfisnorm(GEN bnf, GEN x, long flag)
.
bnf being the
number field data output by bnfinit
, and x being an ideal, this
function tests whether the ideal is principal or not. The result is more
complete than a simple true/false answer and solves a general discrete
logarithm problem. Assume the class group is ⨁ (ℤ/diℤ)gi
(where the generators gi and their orders di are respectively
given by bnf.gen
and bnf.cyc
). The routine returns a row vector
[e,t], where e is a vector of exponents 0 ≤ ei < di, and t
is a number field element such that
x = (t) ∏i giei.
For given gi (i.e. for a given bnf
), the ei are unique,
and t is unique modulo units.
In particular, x is principal if and only if e is the zero vector. Note that the empty vector, which is returned when the class number is 1, is considered to be a zero vector (of dimension 0).
? K = bnfinit(y^2+23); ? K.cyc %2 = [3] ? K.gen %3 = [[2, 0; 0, 1]] \\ a prime ideal above 2 ? P = idealprimedec(K,3)[1]; \\ a prime ideal above 3 ? v = bnfisprincipal(K, P) %5 = [[2]~, [3/4, 1/4]~] ? idealmul(K, v[2], idealfactorback(K, K.gen, v[1])) %6 = [3 0] [0 1] ? % == idealhnf(K, P) %7 = 1
The binary digits of flag mean:
* 1: If set, outputs [e,t] as explained above, otherwise returns only e, which is easier to compute. The following idiom only tests whether an ideal is principal:
is_principal(bnf, x) = !bnfisprincipal(bnf,x,0);
* 2: It may not be possible to recover t, given the initial accuracy
to which the bnf
structure was computed. In that case, a warning is
printed and t is set equal to the empty vector []~
. If this bit is
set, increase the precision and recompute needed quantities until t can be
computed. Warning: setting this may induce lengthy computations, and
the result may be too large to be physically representable in any case.
You should consider using flag = 4 instead.
* 4: Return t in factored form (compact representation),
as a small product of S-units for a small set of finite places S,
possibly with huge exponents. This kind of result can be cheaply mapped to
K*/(K*)ℓ or to ℂ or ℚp to bounded accuracy and this
is usually enough for applications. Explicitly expanding such a compact
representation is possible using nffactorback
but may be very
costly. The algorithm is guaranteed to succeed if the bnf
was computed
using bnfinit(,1)
. If not, the algorithm may fail to compute a huge
generator in this case (and replace it by []~
). This is orders of
magnitude faster than flag = 2 when the generators are indeed large.
The library syntax is GEN bnfisprincipal0(GEN bnf, GEN x, long flag)
.
Instead of the above hardcoded numerical flags, one should
rather use an or-ed combination of the symbolic flags nf_GEN
(include
generators, possibly a place holder if too difficult), nf_GENMAT
(include generators in compact form) and
nf_FORCE
(insist on finding the generators, a no-op if nf_GENMAT
is included).
This function is obsolete, use bnfisunit
.
The library syntax is GEN bnfissunit(GEN bnf, GEN sfu, GEN x)
.
bnf being the number field data
output by bnfinit
and x being an algebraic number (type integer,
rational or polmod), this outputs the decomposition of x on the fundamental
units and the roots of unity if x is a unit, the empty vector otherwise.
More precisely, if u1,...,ur are the fundamental units, and ζ
is the generator of the group of roots of unity (bnf.tu
), the output is
a vector [x1,...,xr,xr+1] such that x = u1x1...
urxr.ζxr+1. The xi are integers but the last one
(i = r+1) is only defined modulo the order w of ζ and is guaranteed
to be in [0,w[.
Note that bnf need not contain the fundamental units explicitly: it may contain the placeholder 0 instead:
? setrand(1); bnf = bnfinit(x^2-x-100000); ? bnf.fu %2 = 0 ? u = [119836165644250789990462835950022871665178127611316131167, \ 379554884019013781006303254896369154068336082609238336]~; ? bnfisunit(bnf, u) %3 = [-1, 0]~
The given u is 1/u1, where u1 is the fundamental
unit implicitly stored in bnf. In this case, u1 was not computed
and stored in algebraic form since the default accuracy was too low. Re-run
the bnfinit
command at \g1
or higher to see such diagnostics.
This function allows x to be given in factored form, but it then assumes that x is an actual unit. (Because it is general too costly to check whether this is the case.)
? { v = [2, 85; 5, -71; 13, -162; 17, -76; 23, -37; 29, -104; [224, 1]~, -66; [-86, 1]~, 86; [-241, 1]~, -20; [44, 1]~, 30; [124, 1]~, 11; [125, -1]~, -11; [-214, 1]~, 33; [-213, -1]~, -33; [189, 1]~, 74; [190, -1]~, 104; [-168, 1]~, 2; [-167, -1]~, -8]; } ? bnfisunit(bnf,v) %5 = [1, 0]~
Note that v is the fundamental unit of bnf
given in
compact (factored) form.
If the argument U
is present, as output by bnfunits(bnf, S)
,
then the function decomposes x on the S-units generators given in
U[1]
.
? bnf = bnfinit(x^4 - x^3 + 4*x^2 + 3*x + 9, 1); ? bnf.sign %2 = [0, 2] ? S = idealprimedec(bnf,5); #S %3 = 2 ? US = bnfunits(bnf,S); ? g = US[1]; #g \\ #S = #g, four S-units generators, in factored form %5 = 4 ? g[1] %6 = [[6, -3, -2, -2]~ 1] ? g[2] %7 = [[-1, 1/2, -1/2, -1/2]~ 1] [ [4, -2, -1, -1]~ 1] ? [nffactorback(bnf, x) | x <- g] %8 = [[6, -3, -2, -2]~, [-5, 5, 0, 0]~, [-1, 1, -1, 0]~, [1, -1, 0, 0]~] ? u = [10,-40,24,11]~; ? a = bnfisunit(bnf, u, US) %9 = [2, 0, 1, 4]~ ? nffactorback(bnf, g, a) \\ prodi g[i]^a[i] still in factored form %10 = [[6, -3, -2, -2]~ 2] [ [0, 0, -1, -1]~ 1] [ [2, -1, -1, 0]~ -2] [ [1, 1, 0, 0]~ 2] [ [-1, 1, 1, 1]~ -1] [ [1, -1, 0, 0]~ 4] ? nffactorback(bnf,%) \\ u = prodi g[i]^a[i] %11 = [10, -40, 24, 11]~
The library syntax is GEN bnfisunit0(GEN bnf, GEN x, GEN U = NULL)
.
Also available is GEN bnfisunit(GEN bnf, GEN x)
for U =
NULL
.
Let bnf be a bnf structure attached to the number field F and let l be a prime number (hereafter denoted ℓ for typographical reasons). Return the logarithmic ℓ-class group ~{Cl}F of F. This is an abelian group, conjecturally finite (known to be finite if F/ℚ is abelian). The function returns if and only if the group is indeed finite (otherwise it would run into an infinite loop). Let S = { 𝔭1,..., 𝔭k} be the set of ℓ-adic places (maximal ideals containing ℓ). The function returns [D, G(ℓ), G'], where
* D is the vector of elementary divisors for ~{Cl}F.
* G(ℓ) is the vector of elementary divisors for the (conjecturally finite) abelian group ~{Cl}(ℓ) = { 𝔞 = ∑i ≤ k ai 𝔭i : degF 𝔞 = 0}, where the 𝔭i are the ℓ-adic places of F; this is a subgroup of ~{Cl}.
* G' is the vector of elementary divisors for the ℓ-Sylow Cl' of the S-class group of F; the group ~{Cl} maps to Cl' with a simple co-kernel.
The library syntax is GEN bnflog(GEN bnf, GEN l)
.
Let nf be a nf structure attached to a number field F, and let l be a prime number (hereafter denoted ℓ). The ℓ-adified group of id\`{e}les of F quotiented by the group of logarithmic units is identified to the ℓ-group of logarithmic divisors ⨁ ℤℓ [𝔭], generated by the maximal ideals of F.
The degree map degF is additive with values in ℤℓ,
defined by degF 𝔭 = ~{f}𝔭 degℓ p,
where the integer ~{f}𝔭 is as in bnflogef
and
degℓ p
is logℓ p for p ! = ℓ, logℓ (1 + ℓ) for
p = ℓ ! = 2 and logℓ (1 + 22) for p = ℓ = 2.
Let A = ∏ 𝔭n𝔭 be an ideal and let ~{A} = ∑ n𝔭 [𝔭] be the attached logarithmic divisor. Return the exponential of the ℓ-adic logarithmic degree degF A, which is a natural number.
The library syntax is GEN bnflogdegree(GEN nf, GEN A, GEN l)
.
Let nf be a nf structure attached to a number field F and let pr be a prid structure attached to a maximal ideal 𝔭 / p. Return [~{e}(F𝔭 / ℚp), ~{f}(F𝔭 / ℚp)] the logarithmic ramification and residue degrees. Let ℚpc/ℚp be the cyclotomic ℤp-extension, then ~{e} = [F𝔭 : F𝔭 ∩ ℚpc] and ~{f} = [F𝔭 ∩ ℚpc : ℚp]. Note that ~{e}~{f} = e(𝔭/p) f(𝔭/p), where e(𝔭/p) and f(𝔭/p) denote the usual ramification and residue degrees.
? F = nfinit(y^6 - 3*y^5 + 5*y^3 - 3*y + 1); ? bnflogef(F, idealprimedec(F,2)[1]) %2 = [6, 1] ? bnflogef(F, idealprimedec(F,5)[1]) %3 = [1, 2]
The library syntax is GEN bnflogef(GEN nf, GEN pr)
.
bnf being as output by
bnfinit
, computes the narrow class group of bnf. The output is
a 3-component row vector v analogous to the corresponding class group
component bnf.clgp
: the first component
is the narrow class number v.no
, the second component is a vector
containing the SNF cyclic components v.cyc
of
the narrow class group, and the third is a vector giving the generators of
the corresponding v.gen
cyclic groups. Note that this function is a
special case of bnrinit
; the bnf need not contain fundamental
units.
The library syntax is GEN bnfnarrow(GEN bnf)
.
bnf being as output by
bnfinit
, this computes an r1 x (r1+r2-1) matrix having
±1
components, giving the signs of the real embeddings of the fundamental units.
The following functions compute generators for the totally positive units:
/* exponents of totally positive units generators on K.tu, K.fu */ tpuexpo(K)= { my(M, S = bnfsignunit(K), [m,n] = matsize(S)); \\ m = K.r1, n = r1+r2-1 S = matrix(m,n, i,j, if (S[i,j] < 0, 1,0)); S = concat(vectorv(m,i,1), S); \\ add sign(-1) M = matkermod(S, 2); if (M, mathnfmodid(M, 2), 2*matid(n+1)) } /* totally positive fundamental units of bnf K */ tpu(K)= { my(ex = tpuexpo(K)[,^1]); \\ remove ex[,1], corresponds to 1 or -1 my(v = concat(K.tu[2], K.fu)); [ nffactorback(K, v, c) | c <- ex]; }
The library syntax is GEN signunits(GEN bnf)
.
Computes the fundamental S-units of the
number field bnf (output by bnfinit
), where S is a list of
prime ideals (output by idealprimedec
). The output is a vector v with
6 components.
v[1] gives a minimal system of (integral) generators of the S-unit group modulo the unit group.
v[2] contains technical data needed by bnfissunit
.
v[3] is an obsoleted component, now the empty vector.
v[4] is the S-regulator (this is the product of the regulator, the S-class number and the natural logarithms of the norms of the ideals in S).
v[5] gives the S-class group structure, in the usual abelian group format: a vector whose three components give in order the S-class number, the cyclic components and the generators.
v[6] is a copy of S.
The library syntax is GEN bnfsunit(GEN bnf, GEN S, long prec)
.
Also available is
GEN sunits_mod_units(GEN bnf, GEN S)
which returns only v[1].
Return the fundamental units of the number field bnf output by bnfinit; if S is present and is a list of prime ideals, compute fundamental S-units instead. The first component of the result contains independent integral S-units generators: first nonunits, then r1+r2-1 fundamental units, then the torsion unit. The result may be used as an optional argument to bnfisunit. The units are given in compact form: no expensive computation is attempted if the bnf does not already contain units.
? bnf = bnfinit(x^4 - x^3 + 4*x^2 + 3*x + 9, 1); ? bnf.sign \\ r1 + r2 - 1 = 1 %2 = [0, 2] ? U = bnfunits(bnf); u = U[1]; ? #u \\ r1 + r2 = 2 units %5 = 2; ? u[1] \\ fundamental unit as factorization matrix %6 = [[0, 0, -1, -1]~ 1] [[2, -1, -1, 0]~ -2] [ [1, 1, 0, 0]~ 2] [ [-1, 1, 1, 1]~ -1] ? u[2] \\ torsion unit as factorization matrix %7 = [[1, -1, 0, 0]~ 1] ? [nffactorback(bnf, z) | z <- u] \\ same units in expanded form %8 = [[-1, 1, -1, 0]~, [1, -1, 0, 0]~]
Now an example involving S-units for a nontrivial S:
? S = idealprimedec(bnf,5); #S %9 = 2 ? US = bnfunits(bnf, S); uS = US[1]; ? g = [nffactorback(bnf, z) | z <- uS] \\ now 4 units %11 = [[6, -3, -2, -2]~, [-5, 5, 0, 0]~, [-1, 1, -1, 0]~, [1, -1, 0, 0]~] ? bnfisunit(bnf,[10,-40,24,11]~) %12 = []~ \\ not a unit ? e = bnfisunit(bnf, [10,-40,24,11]~, US) %13 = [2, 0, 1, 4]~ \\ ...but an S-unit ? nffactorback(bnf, g, e) %14 = [10, -40, 24, 11]~ ? nffactorback(bnf, uS, e) \\ in factored form %15 = [[6, -3, -2, -2]~ 2] [ [0, 0, -1, -1]~ 1] [ [2, -1, -1, 0]~ -2] [ [1, 1, 0, 0]~ 2] [ [-1, 1, 1, 1]~ -1] [ [1, -1, 0, 0]~ 4]
Note that in more complicated cases, any nffactorback
fully expanding an element in factored form could be very expensive.
On the other hand, the final example expands a factorization whose components
are themselves in factored form, hence the result is a factored form:
this is a cheap operation.
The library syntax is GEN bnfunits(GEN bnf, GEN S = NULL)
.
Let bnr be the number field data output by bnrinit
and
H be a square matrix defining a congruence subgroup of the
ray class group corresponding to bnr (the trivial congruence subgroup
if omitted). This function returns, for each character χ of the ray
class group which is trivial on H, the value at s = 1 (or s = 0) of the
abelian L-function attached to χ. For the value at s = 0, the
function returns in fact for each χ a vector [rχ, cχ] where
L(s, χ) = c.sr + O(sr + 1)
near 0.
The argument flag is optional, its binary digits mean 1: compute at s = 0 if unset or s = 1 if set, 2: compute the primitive L-function attached to χ if unset or the L-function with Euler factors at prime ideals dividing the modulus of bnr removed if set (that is LS(s, χ), where S is the set of infinite places of the number field together with the finite prime ideals dividing the modulus of bnr), 3: return also the character if set.
K = bnfinit(x^2-229); bnr = bnrinit(K,1); bnrL1(bnr)
returns the order and the first nonzero term of L(s, χ) at s = 0 where χ runs through the characters of the class group of K = ℚ(sqrt{229}). Then
bnr2 = bnrinit(K,2); bnrL1(bnr2,,2)
returns the order and the first nonzero terms of LS(s, χ) at s = 0
where χ runs through the characters of the class group of K and S is
the set of infinite places of K together with the finite prime 2. Note
that the ray class group modulo 2 is in fact the class group, so
bnrL1(bnr2,0)
returns the same answer as bnrL1(bnr,0)
.
This function will fail with the message
*** bnrL1: overflow in zeta_get_N0 [need too many primes].
if the approximate functional equation requires us to sum too many terms (if the discriminant of K is too large).
The library syntax is GEN bnrL1(GEN bnr, GEN H = NULL, long flag, long prec)
.
Returns all characters χ on G such that χ(gi) = e(vi), where e(x) = exp(2iπ x). G is allowed to be a bnr struct (representing a ray class group) or a znstar (representing (ℤ/Nℤ)*). If v is omitted, returns all characters that are trivial on the gi. Else the vectors g and v must have the same length, the gi must be elements of G, and each vi is a rational number whose denominator must divide the order of gi in G.
For convenience, the vector of the gi
can be replaced by a matrix whose columns give their discrete logarithm
in G, for instance as given by bnrisprincipal
if G is a bnr;
in this particular case, G can be any finite abelian group
given by a vector of elementary divisors.
? G = bnrinit(bnfinit(x), [160,[1]], 1); /* (Z/160Z)* */ ? G.cyc %2 = [8, 4, 2] ? g = G.gen; ? bnrchar(G, g, [1/2,0,0]) %4 = [[4, 0, 0]] \\ a unique character ? bnrchar(G, [g[1],g[3]]) \\ all characters trivial on g[1] and g[3] %5 = [[0, 1, 0], [0, 2, 0], [0, 3, 0], [0, 0, 0]] ? bnrchar(G, [1,0,0;0,1,0;0,0,2]) %6 = [[0, 0, 1], [0, 0, 0]] \\ characters trivial on given subgroup ? G = znstar(75, 1); ? bnrchar(G, [2, 7], [11/20, 1/4]) %8 = [[1, 1]] \\ Dirichlet char: chi(2) = e(11/20), chi(7) = e(1/4)
The library syntax is GEN bnrchar(GEN G, GEN g, GEN v = NULL)
.
bnr being as output by bnrinit
, returns a relative equation
for the class field corresponding to the congruence group defined by
(bnr,subgp) (the full ray class field if subgp is
omitted). The subgroup can also be a t_INT
n,
meaning n.Clf. The function also handles a vector of
subgroup, e.g, from subgrouplist
and returns the vector of individual
results in this case.
If flag = 0, returns a vector of polynomials such that the compositum of the corresponding fields is the class field; if flag = 1 returns a single polynomial; if flag = 2 returns a single absolute polynomial.
? bnf = bnfinit(y^3+14*y-1); bnf.cyc %1 = [4, 2] ? pol = bnrclassfield(bnf,,1) \\ Hilbert class field %2 = x^8 - 2*x^7 + ... + Mod(11*y^2 - 82*y + 116, y^3 + 14*y - 1) ? rnfdisc(bnf,pol)[1] %3 = 1 ? bnr = bnrinit(bnf,3*5*7); bnr.cyc %4 = [24, 12, 12, 2] ? bnrclassfield(bnr,2) \\ maximal 2-elementary subextension %5 = [x^2 + (-21*y - 105), x^2 + (-5*y - 25), x^2 + (-y - 5), x^2 + (-y - 1)] \\ quadratic extensions of maximal conductor ? bnrclassfield(bnr, subgrouplist(bnr,[2])) %6 = [[x^2 - 105], [x^2 + (-105*y^2 - 1260)], [x^2 + (-105*y - 525)], [x^2 + (-105*y - 105)]] ? #bnrclassfield(bnr,subgrouplist(bnr,[2],1)) \\ all quadratic extensions %7 = 15
When the subgroup contains n Clf, where n is
fixed, it is advised to directly compute the bnr
modulo n to avoid
expensive discrete logarithms:
? bnf = bnfinit(y^2-5); p = 1594287814679644276013; ? bnr = bnrinit(bnf,p); \\ very slow time = 24,146 ms. ? bnrclassfield(bnr, 2) \\ ... even though the result is trivial %3 = [x^2 - 1594287814679644276013] ? bnr2 = bnrinit(bnf,p,,2); \\ now fast time = 1 ms. ? bnrclassfield(bnr2, 2) %5 = [x^2 - 1594287814679644276013]
This will save a lot of time when the modulus contains a maximal ideal whose residue field is large.
The library syntax is GEN bnrclassfield(GEN bnr, GEN subgp = NULL, long flag, long prec)
.
Let A, B, C define a class field L over a ground field K
(of type [bnr]
,
[bnr, subgroup]
,
or [bnf, modulus]
,
or [bnf, modulus,subgroup]
,
Section se:CFT); this function returns the relative degree [L:K].
In particular if A is a bnf (with units), and B a modulus, this function returns the corresponding ray class number modulo B. One can input the attached bid (with generators if the subgroup C is non trivial) for B instead of the module itself, saving some time.
This function is faster than bnrinit
and should be used if only the
ray class number is desired. See bnrclassnolist
if you need ray class
numbers for all moduli less than some bound.
The library syntax is GEN bnrclassno0(GEN A, GEN B = NULL, GEN C = NULL)
.
Also available is
GEN bnrclassno(GEN bnf,GEN f)
to compute the ray class number
modulo f.
bnf being as
output by bnfinit
, and list being a list of moduli (with units) as
output by ideallist
or ideallistarch
, outputs the list of the
class numbers of the corresponding ray class groups. To compute a single
class number, bnrclassno
is more efficient.
? bnf = bnfinit(x^2 - 2); ? L = ideallist(bnf, 100, 2); ? H = bnrclassnolist(bnf, L); ? H[98] %4 = [1, 3, 1] ? l = L[1][98]; ids = vector(#l, i, l[i].mod[1]) %5 = [[98, 88; 0, 1], [14, 0; 0, 7], [98, 10; 0, 1]]
The weird l[i].mod[1]
, is the first component of l[i].mod
, i.e.
the finite part of the conductor. (This is cosmetic: since by construction
the Archimedean part is trivial, I do not want to see it). This tells us that
the ray class groups modulo the ideals of norm 98 (printed as %5
) have
respectively order 1, 3 and 1. Indeed, we may check directly:
? bnrclassno(bnf, ids[2]) %6 = 3
The library syntax is GEN bnrclassnolist(GEN bnf, GEN list)
.
Given two abelian extensions A = [bnr1, H1]
and
B = [bnr2, H2]
, where bnr1
and bnr2
are two bnr
structures attached to the same base field, return their compositum
as [bnr, H]
. The modulus attached to bnr
need not be the
conductor of the compositum.
? Q = bnfinit(y); ? bnr1 = bnrinit(Q, [7, [1]]); bnr1.cyc %2 = [6] ? bnr2 = bnrinit(Q, [13, [1]]); bnr2.cyc %3 = [12] ? H1 = Mat(2); bnrclassfield(bnr1, H1) %4 = [x^2 + 7] ? H2 = Mat(2); bnrclassfield(bnr2, H2) %5 = [x^2 - 13] ? [bnr,H] = bnrcompositum([bnr1, H1], [bnr2,H2]); ? bnrclassfield(bnr,H) %7 = [x^2 - 13, x^2 + 7]
The library syntax is GEN bnrcompositum(GEN A, GEN B)
.
Conductor f of the subfield of a ray class field as defined by [A,B,C]
(of type [bnr]
,
[bnr, subgroup]
,
[bnf, modulus]
or
[bnf, modulus, subgroup]
,
Section se:CFT)
If flag = 0, returns f.
If flag = 1, returns [f, Clf, H], where Clf is the ray class group modulo f, as a finite abelian group; finally H is the subgroup of Clf defining the extension.
If flag = 2, returns [f, bnr(f), H], as above except Clf is
replaced by a bnr
structure, as output by bnrinit
(,f), without
generators unless the input contained a bnr with generators.
In place of a subgroup H, this function also accepts a character
chi
= (aj), expressed as usual in terms of the generators
bnr.gen
: χ(gj) = exp(2iπ aj / dj), where gj has
order dj = bnr.cyc[j]
. In which case, the function returns
respectively
If flag = 0, the conductor f of Ker χ.
If flag = 1, [f, Clf, χf], where χf is χ expressed on the minimal ray class group, whose modulus is the conductor.
If flag = 2, [f, bnr(f), χf].
Note. Using this function with flag ! = 0 is usually a bad idea and kept for compatibility and convenience only: flag = 1 has always been useless, since it is no faster than flag = 2 and returns less information; flag = 2 is mostly OK with two subtle drawbacks:
* it returns the full bnr attached to the full ray class
group, whereas in applications we only need Clf modulo N-th powers,
where N is any multiple of the exponent of Clf/H. Computing directly the
conductor, then calling bnrinit
with optional argument N avoids this
problem.
* computing the bnr needs only be done once for each conductor, which is not possible using this function.
For maximal efficiency, the recommended procedure is as follows. Starting
from data (character or congruence subgroups) attached to a modulus m,
we can first compute the conductors using this function with default flag =
0. Then for all data with a common conductor f | m, compute (once!) the
bnr attached to f using bnrinit
(modulo N-th powers for
a suitable N!) and finally map original data to the new bnr using
bnrmap
.
The library syntax is GEN bnrconductor0(GEN A, GEN B = NULL, GEN C = NULL, long flag)
.
Also available are GEN bnrconductor(GEN bnr, GEN H, long flag)
and GEN bnrconductormod(GEN bnr, GEN H, long flag, GEN cycmod)
which returns ray class groups modulo cycmod
-th powers.
This function is obsolete, use bnrconductor.
The library syntax is GEN bnrconductorofchar(GEN bnr, GEN chi)
.
A, B, C defining a class field L over a ground field K
(of type [bnr]
,
[bnr, subgroup]
,
[bnr, character]
,
[bnf, modulus]
or
[bnf, modulus, subgroup]
,
Section se:CFT), outputs data [N,r1,D] giving the discriminant and
signature of L, depending on the binary digits of flag:
* 1: if this bit is unset, output absolute data related to L/ℚ: N is the absolute degree [L:ℚ], r1 the number of real places of L, and D the discriminant of L/ℚ. Otherwise, output relative data for L/K: N is the relative degree [L:K], r1 is the number of real places of K unramified in L (so that the number of real places of L is equal to r1 times N), and D is the relative discriminant ideal of L/K.
* 2: if this bit is set and if the modulus is not the conductor of L, only return 0.
The library syntax is GEN bnrdisc0(GEN A, GEN B = NULL, GEN C = NULL, long flag)
.
bnf being as output by bnfinit
(with units), computes a
list of discriminants of Abelian extensions of the number field by increasing
modulus norm up to bound bound. The ramified Archimedean places are
given by arch; all possible values are taken if arch is omitted.
The alternative syntax bnrdisclist
(bnf,list) is
supported, where list is as output by ideallist
or
ideallistarch
(with units), in which case arch is disregarded.
The output v is a vector, where v[k] is itself a vector w, whose length is the number of ideals of norm k.
* We consider first the case where arch was specified. Each component of w corresponds to an ideal m of norm k, and gives invariants attached to the ray class field L of bnf of conductor [m, arch]. Namely, each contains a vector [m,d,r,D] with the following meaning: m is the prime ideal factorization of the modulus, d = [L:ℚ] is the absolute degree of L, r is the number of real places of L, and D is the factorization of its absolute discriminant. We set d = r = D = 0 if m is not the finite part of a conductor.
* If arch was omitted, all t = 2r1 possible values are taken and a component of w has the form [m, [[d1,r1,D1],..., [dt,rt,Dt]]], where m is the finite part of the conductor as above, and [di,ri,Di] are the invariants of the ray class field of conductor [m,vi], where vi is the i-th Archimedean component, ordered by inverse lexicographic order; so v1 = [0,...,0], v2 = [1,0...,0], etc. Again, we set di = ri = Di = 0 if [m,vi] is not a conductor.
Finally, each prime ideal pr = [p,α,e,f,β] in the prime factorization m is coded as the integer p.n2+(f-1).n+(j-1), where n is the degree of the base field and j is such that
pr = idealprimedec(nf,p)[j]
.
m can be decoded using bnfdecodemodule
.
Note that to compute such data for a single field, either bnrclassno
or bnrdisc
are (much) more efficient.
The library syntax is GEN bnrdisclist0(GEN bnf, GEN bound, GEN arch = NULL)
.
Apply the automorphism given by its matrix mat to the congruence
subgroup H given as a HNF matrix.
The matrix mat can be computed with bnrgaloismatrix
.
The library syntax is GEN bnrgaloisapply(GEN bnr, GEN mat, GEN H)
.
Return the matrix of the action of the automorphism aut of the base
field bnf.nf
on the generators of the ray class field bnr.gen
.
The automorphism
aut can be given as a polynomial, an algebraic number, or a vector of
automorphisms and must stabilize the modulus bnr.mod
. We also
allow a Galois group as output by galoisinit
, in which case a
vector of matrices is returned corresponding to the generators
aut.gen
.
Note: This function only makes sense when the ray class field attached to
bnr is Galois, which is not checked.
The generators bnr.gen
need not be explicitly computed in the input
bnr, which saves time: the result is well defined in this case also.
? K = bnfinit(a^4-3*a^2+253009); B = bnrinit(K,9); B.cyc %1 = [8400, 12, 6, 3] ? G = nfgaloisconj(K) %2 = [-a, a, -1/503*a^3 + 3/503*a, 1/503*a^3 - 3/503*a]~ ? bnrgaloismatrix(B, G[2]) \\ G[2] = Id ... %3 = [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1] ? bnrgaloismatrix(B, G[3]) \\ automorphism of order 2 %4 = [799 0 0 2800] [ 0 7 0 4] [ 4 0 5 2] [ 0 0 0 2] ? M = %^2; for (i=1, #B.cyc, M[i,] %= B.cyc[i]); M %5 = \\ acts on ray class group as automorphism of order 2 [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 1]
See bnrisgalois
for further examples.
The library syntax is GEN bnrgaloismatrix(GEN bnr, GEN aut)
.
When aut is a polynomial or an algebraic number,
GEN bnrautmatrix(GEN bnr, GEN aut)
is available.
bnf is as
output by bnfinit
(including fundamental units), f is a modulus,
initializes data linked to the ray class group structure corresponding to
this module, a so-called bnr
structure. One can input the attached
bid with generators for f instead of the module itself, saving some
time. (As in idealstar
, the finite part of the conductor may be given
by a factorization into prime ideals, as produced by idealfactor
.)
If the positive integer cycmod
is present, only compute the ray class
group modulo cycmod
, which may save a lot of time when some maximal
ideals in f have a huge residue field. In applications, we are given
a congruence subgroup H and study the class field attached to
Clf/H. If that finite Abelian group has an exponent which divides
cycmod
, then we have changed nothing theoretically, while trivializing
expensive discrete logs in residue fields (since computations can be
made modulo cycmod
-th powers). This is useful in bnrclassfield
,
for instance when computing p-elementary extensions.
The following member functions are available
on the result: .bnf
is the underlying bnf,
.mod
the modulus, .bid
the bid
structure attached to the
modulus; finally, .clgp
, .no
, .cyc
, .gen
refer to the
ray class group (as a finite abelian group), its cardinality, its elementary
divisors, its generators (only computed if flag = 1).
The last group of functions are different from the members of the underlying
bnf, which refer to the class group; use bnr.bnf.xxx
to access these, e.g. bnr.bnf.cyc
to get the cyclic decomposition
of the class group.
They are also different from the members of the underlying bid, which
refer to (ℤK/f)*; use bnr.bid.xxx
to access these,
e.g. bnr.bid.no
to get φ(f).
If flag = 0 (default), the generators of the ray class group are not
explicitly computed, which saves time. Hence bnr.gen
would
produce an error. Note that implicit generators are still fixed and stored
in the bnr (and guaranteed to be the same for fixed bnf and
bid inputs), in terms of bnr.bnf.gen
and bnr.bid.gen
.
The computation which is not performed is the expansion of such products
in the ray class group so as to fix eplicit ideal representatives.
If flag = 1, as the default, except that generators are computed.
The library syntax is GEN bnrinitmod(GEN bnf, GEN f, long flag, GEN cycmod = NULL)
.
Instead of the above hardcoded numerical flags, one should rather use
GEN Buchraymod(GEN bnf, GEN module, long flag, GEN cycmod)
where an omitted cycmod
is coded as NULL
and flag is an or-ed
combination of nf_GEN
(include generators) and nf_INIT
(if
omitted, return just the cardinality of the ray class group and its structure),
possibly 0. Or simply
GEN Buchray(GEN bnf, GEN module, long flag)
when cycmod
is NULL
.
Fast variant of bnrconductor
(A,B,C); A, B, C represent
an extension of the base field, given by class field theory
(see Section se:CFT). Outputs 1 if this modulus is the conductor, and 0
otherwise. This is slightly faster than bnrconductor
when the
character or subgroup is not primitive.
The library syntax is long bnrisconductor0(GEN A, GEN B = NULL, GEN C = NULL)
.
Check whether the class field attached to the subgroup H is Galois
over the subfield of bnr.nf
fixed by the group gal, which can be
given as output by galoisinit
, or as a matrix or a vector of matrices as
output by bnrgaloismatrix
, the second option being preferable, since it
saves the recomputation of the matrices. Note: The function assumes that the
ray class field attached to bnr is Galois, which is not checked.
In the following example, we lists the congruence subgroups of subextension of degree at most 3 of the ray class field of conductor 9 which are Galois over the rationals.
? K = bnfinit(a^4-3*a^2+253009); B = bnrinit(K,9); G = galoisinit(K); ? [H | H<-subgrouplist(B,3), bnrisgalois(B,G,H)]; time = 160 ms. ? M = bnrgaloismatrix(B,G); ? [H | H<-subgrouplist(B,3), bnrisgalois(B,M,H)] time = 1 ms.
The second computation is much faster since bnrgaloismatrix(B,G)
is
computed only once.
The library syntax is long bnrisgalois(GEN bnr, GEN gal, GEN H)
.
Let bnr be the ray class group data output by
bnrinit
(,,1) and let x be an ideal in any form, coprime
to the modulus f = bnr.mod
. Solves the discrete logarithm problem
in the ray class group, with respect to the generators bnr.gen
,
in a way similar to bnfisprincipal
. If x is not coprime to the
modulus of bnr the result is undefined. Note that bnr need not
contain the ray class group generators, i.e. it may be created with
bnrinit
(,,0); in that case, although bnr.gen
is undefined, we
can still fix natural generators for the ray class group (in terms of the
generators in bnr.bnf.gen
and bnr.bid.gen
) and compute with
respect to them.
The binary digits of flag (default flag = 1) mean:
* 1: If set returns a 2-component vector [e,α] where e is the vector of components of x on the ray class group generators, α is an element congruent to 1 mod* f such that x = α ∏i giei. If unset, returns only e.
* 4: If set, returns [e,α] where α is given in factored form (compact representation). This is orders of magnitude faster.
? K = bnfinit(x^2 - 30); bnr = bnrinit(K, [4, [1,1]]); ? bnr.clgp \\ ray class group is isomorphic to Z/4 x Z/2 x Z/2 %2 = [16, [4, 2, 2]] ? P = idealprimedec(K, 3)[1]; \\ the ramified prime ideal above 3 ? bnrisprincipal(bnr,P) \\ bnr.gen undefined ! %5 = [[3, 0, 0]~, 9] ? bnrisprincipal(bnr,P, 0) \\ omit principal part %5 = [3, 0, 0]~ ? bnr = bnrinit(bnr, bnr.bid, 1); \\ include explicit generators ? bnrisprincipal(bnr,P) \\ ... alpha is different ! %7 = [[3, 0, 0]~, 1/128625]
It may be surprising that the generator α is different
although the underlying bnf and bid are the same. This defines
unique generators for the ray class group as ideal classes, whether
we use bnrinit(,0)
or bnrinit(,1)
. But the actual ideal
representatives (implicit if flag = 0, computed and stored in the
bnr if flag = 1) are in general different and this is what
happens here. Indeed, the implicit generators are naturally expressed
in terms of bnr.bnf.gen
and bnr.bid.gen
and then
expanded and simplified (in the same ideal class) so that we obtain ideal
representatives for bnr.gen
which are as simple as possible.
And indeed the quotient of the two α found is 1 modulo the
conductor (and positive at the infinite places it contains), and this is the
only guaranteed property.
Beware that, when bnr
is generated using bnrinit(, cycmod)
, the
results are given in Clf modulo cycmod
-th powers:
? bnr2 = bnrinit(K, bnr.mod,, 2); \\ modulo squares ? bnr2.clgp %9 = [8, [2, 2, 2]] \\ bnr.clgp tensored by Z/2Z ? bnrisprincipal(bnr2,P, 0) %10 = [1, 0, 0]~
The library syntax is GEN bnrisprincipal(GEN bnr, GEN x, long flag)
.
Instead of hardcoded numerical flags, one should rather use
GEN isprincipalray(GEN bnr, GEN x)
for flag = 0, and if you
want generators:
bnrisprincipal(bnr, x, nf_GEN)
Also available is
GEN bnrisprincipalmod(GEN bnr, GEN x, GEN mod, long flag)
that returns the discrete logarithm of x modulo the t_INT
mod
; the value mod = NULL
is treated as 0 (full discrete
logarithm), and flag = 1 is not allowed if mod
is set.
This function has two different uses:
* if A and B are bnr structures for the same bnf attached
to moduli mA and mB with mB | mA, return the canonical surjection
from A to B, i.e. from the ray class group moodulo mA to the ray
class group modulo mB. The map is coded by a triple
[M,cycA,cycB]:
M gives the image of the fixed ray class group generators of A in
terms of the ones in B, cycA and cycB are the cyclic
structures A.cyc
and B.cyc
respectively. Note that this function
does not need A or B to contain explicit generators for the ray
class groups: they may be created using bnrinit(,0)
.
If B is only known modulo N-th powers (from bnrinit(,N)
), the result
is correct provided N is a multiple of the exponent of A.
* if A is a projection map as above and B is either a congruence
subgroup H, or a ray class character χ, or a discrete logarithm
(from bnrisprincipal
) modulo mA whose conductor
divides mB, return the image of the subgroup (resp. the character, the
discrete logarighm) as defined modulo mB. The main use of this variant is
to compute the primitive subgroup or character attached to a bnr modulo
their conductor. This is more efficient than bnrconductor
in two
respects: the bnr attached to the conductor need only be computed once
and, most importantly, the ray class group can be computed modulo N-th
powers, where N is a multiple of the exponent of Clm_{A} / H
(resp.
of the order of χ). Whereas bnrconductor
is specified to return a
bnr attached to the full ray class group, which may lead to untractable
discrete logarithms in the full ray class group instead of a tiny quotient.
The library syntax is GEN bnrmap(GEN A, GEN B)
.
If χ = chi is a character over bnr, not necessarily primitive, let L(s,χ) = ∑id χ(id) N(id)-s be the attached Artin L-function. Returns the so-called Artin root number, i.e. the complex number W(χ) of modulus 1 such that
Λ(1-s,χ) = W(χ) Λ(s,χ)
where Λ(s,χ) = A(χ)s/2γχ(s) L(s,χ) is the enlarged L-function attached to L.
You can set flag = 1 if the character is known to be primitive. Example:
bnf = bnfinit(x^2 - x - 57); bnr = bnrinit(bnf, [7,[1,1]]); bnrrootnumber(bnr, [2,1])
returns the root number of the character χ of
Cl7 oo _{1 oo 2}(ℚ(sqrt{229})) defined by
χ(g1ag2b)
= ζ12aζ2b. Here g1, g2 are the generators of the
ray-class group given by bnr.gen
and ζ1 = e2iπ/N1,
ζ2 = e2iπ/N2 where N1, N2 are the orders of g1
and g2 respectively (N1 = 6 and N2 = 3 as bnr.cyc
readily
tells us).
The library syntax is GEN bnrrootnumber(GEN bnr, GEN chi, long flag, long prec)
.
bnr being as output by bnrinit
, finds a relative equation
for the class field corresponding to the modulus in bnr and the given
congruence subgroup (as usual, omit subgroup if you want the whole ray
class group).
The main variable of bnr must not be x, and the ground field and the
class field must be totally real. When the base field is ℚ, the vastly
simpler galoissubcyclo
is used instead. Here is an example:
bnf = bnfinit(y^2 - 3); bnr = bnrinit(bnf, 5); bnrstark(bnr)
returns the ray class field of ℚ(sqrt{3}) modulo 5. Usually, one wants to apply to the result one of
rnfpolredbest(bnf, pol) \\ compute a reduced relative polynomial rnfpolredbest(bnf, pol, 2) \\ compute a reduced absolute polynomial
The routine uses Stark units and needs to find a suitable auxiliary
conductor, which may not exist when the class field is not cyclic over the
base. In this case bnrstark
is allowed to return a vector of
polynomials defining independent relative extensions, whose compositum
is the requested class field. We decided that it was useful to keep the
extra information thus made available, hence the user has to take the
compositum herself, see nfcompositum
.
Even if it exists, the auxiliary conductor may be so large that later
computations become unfeasible. (And of course, Stark's conjecture may simply
be wrong.) In case of difficulties, try bnrclassfield
:
? bnr = bnrinit(bnfinit(y^8-12*y^6+36*y^4-36*y^2+9,1), 2); ? bnrstark(bnr) *** at top-level: bnrstark(bnr) *** ^ — — — — - *** bnrstark: need 3919350809720744 coefficients in initzeta. *** Computation impossible. ? bnrclassfield(bnr) time = 20 ms. %2 = [x^2 + (-2/3*y^6 + 7*y^4 - 14*y^2 + 3)]
The library syntax is GEN bnrstark(GEN bnr, GEN subgroup = NULL, long prec)
.
bnr being as output by bnrinit
, returns the characteristic
polynomial of the (conjectural) Stark unit corresponding to the modulus in
bnr and the given congruence subgroup (as usual, omit subgroup
if you want the whole ray class group).
The ground field attached to bnr must be totally real and all but one infinite place must become complex in the class field, which must be a quadratic extension of its totally real subfield. Finally, the output is given as a polynomial in x, so the main variable of bnr must not be x. Here is an example:
? bnf = bnfinit(y^2 - 2); ? bnr = bnrinit(bnf, [15, [1,0]]); ? lift(bnrstarkunit(bnr)) %3 = x^8 + (-9000*y - 12728)*x^7 + (57877380*y + 81850978)*x^6 + ... + 1
The library syntax is GEN bnrstarkunit(GEN bnr, GEN subgroup = NULL)
.
Gives as a vector the first b coefficients of the Dedekind zeta function of the number field nf considered as a Dirichlet series.
The library syntax is GEN dirzetak(GEN nf, GEN b)
.
This function is obsolete, use nffactor
.
factorization of the univariate polynomial x
over the number field defined by the (univariate) polynomial t. x may
have coefficients in ℚ or in the number field. The algorithm reduces to
factorization over ℚ (Trager's trick). The direct approach of
nffactor
, which uses van Hoeij's method in a relative setting, is
in general faster.
The main variable of t must be of lower priority than that of x (see Section se:priority). However if nonrational number field elements occur (as polmods or polynomials) as coefficients of x, the variable of these polmods must be the same as the main variable of t. For example
? factornf(x^2 + Mod(y, y^2+1), y^2+1); ? factornf(x^2 + y, y^2+1); \\ these two are OK ? factornf(x^2 + Mod(z,z^2+1), y^2+1) *** at top-level: factornf(x^2+Mod(z,z *** ^ — — — — — — -- *** factornf: inconsistent data in rnf function. ? factornf(x^2 + z, y^2+1) *** at top-level: factornf(x^2+z,y^2+1 *** ^ — — — — — — -- *** factornf: incorrect variable in rnf function.
The library syntax is GEN polfnf(GEN x, GEN t)
.
Let G be the group attached to the galoisinit
structure gal, and
let χ be the character of some representation ρ of the group G,
where a polynomial variable is to be interpreted as an o-th root of 1.
For instance, if [T,o] = galoischartable(gal)
the characters
χ are input as the columns of T
.
Return the degree-1 character detρ as the list of det ρ(g),
where g runs through representatives of the conjugacy classes
in galoisconjclasses(gal)
, with the same ordering.
? P = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; ? polgalois(P) %2 = [10, 1, 1, "D(5) = 5:2"] ? K = nfsplitting(P); ? gal = galoisinit(K); \\ dihedral of order 10 ? [T,o] = galoischartable(gal); ? chi = T[,1]; \\ trivial character ? galoischardet(gal, chi, o) %7 = [1, 1, 1, 1]~ ? [galoischardet(gal, T[,i], o) | i <- [1..#T]] \\ all characters %8 = [[1, 1, 1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~, [1, 1, -1, 1]~]
The library syntax is GEN galoischardet(GEN gal, GEN chi, long o)
.
Let G be the group attached to the galoisinit
structure gal, and
let χ be the character of some representation ρ of the group
G, where a polynomial variable is to be interpreted as an o-th root of
1, e.g., if [T,o] = galoischartable(gal)
and χ is a column of
T
.
Return the list of characteristic polynomials det(1 - ρ(g)T),
where g runs through representatives of the conjugacy classes
in galoisconjclasses(gal)
, with the same ordering.
? T = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1; ? polgalois(T) %2 = [10, 1, 1, "D(5) = 5:2"] ? K = nfsplitting(T); ? gal = galoisinit(K); \\ dihedral of order 10 ? [T,o] = galoischartable(gal); ? o %5 = 5 ? galoischarpoly(gal, T[,1], o) \\ T[,1] is the trivial character %6 = [-x + 1, -x + 1, -x + 1, -x + 1]~ ? galoischarpoly(gal, T[,3], o) %7 = [x^2 - 2*x + 1, x^2 + (y^3 + y^2 + 1)*x + 1, -x^2 + 1, x^2 + (-y^3 - y^2)*x + 1]~
The library syntax is GEN galoischarpoly(GEN gal, GEN chi, long o)
.
Compute the character table of G, where G is the underlying group of
the galoisinit
structure gal. The input gal is also allowed
to be a t_VEC
of permutations that is closed under products.
Let N be the number of conjugacy classes of G.
Return a t_VEC
[M,e] where e ≥ 1 is an integer
and M is a square t_MAT
of size N giving the character table
of G.
* Each column corresponds to an irreducible character; the characters are ordered by increasing dimension and the first column is the trivial character (hence contains only 1's).
* Each row corresponds to a conjugacy class; the conjugacy classes are
ordered as specified by galoisconjclasses(gal)
, in particular the
first row corresponds to the identity and gives the dimension χ(1)
of the irreducible representation attached to the successive characters
χ.
The value M[i,j] of the character j at the conjugacy class i
is represented by a polynomial in y
whose variable should be
interpreted as an e-th root of unity, i.e. as the lift of
Mod(y, polcyclo(e,'y))
(Note that M is the transpose of the usual orientation for character tables.)
The integer e divides the exponent of the group G and is chosen as small as posible; for instance e = 1 when the characters are all defined over ℚ, as is the case for Sn. Examples:
? K = nfsplitting(x^4+x+1); ? gal = galoisinit(K); ? [M,e] = galoischartable(gal); ? M~ \\ take the transpose to get the usual orientation %4 = [1 1 1 1 1] [1 -1 -1 1 1] [2 0 0 -1 2] [3 -1 1 0 -1] [3 1 -1 0 -1] ? e %5 = 1 ? {G = [Vecsmall([1, 2, 3, 4, 5]), Vecsmall([1, 5, 4, 3, 2]), Vecsmall([2, 1, 5, 4, 3]), Vecsmall([2, 3, 4, 5, 1]), Vecsmall([3, 2, 1, 5, 4]), Vecsmall([3, 4, 5, 1, 2]), Vecsmall([4, 3, 2, 1, 5]), Vecsmall([4, 5, 1, 2, 3]), Vecsmall([5, 1, 2, 3, 4]), Vecsmall([5, 4, 3, 2, 1])];} \\G = D10 ? [M,e] = galoischartable(G); ? M~ %8 = [1 1 1 1] [1 -1 1 1] [2 0 -y^3 - y^2 - 1 y^3 + y^2] [2 0 y^3 + y^2 -y^3 - y^2 - 1] ? e %9 = 5
The library syntax is GEN galoischartable(GEN gal)
.
gal being output by galoisinit
,
return the list of conjugacy classes of the underlying group.
The ordering of the classes is consistent with galoischartable
and the trivial class comes first.
? G = galoisinit(x^6+108); ? galoisidentify(G) %2 = [6, 1] \\ S3 ? S = galoisconjclasses(G) %3 = [[Vecsmall([1,2,3,4,5,6])], [Vecsmall([3,1,2,6,4,5]),Vecsmall([2,3,1,5,6,4])], [Vecsmall([6,5,4,3,2,1]),Vecsmall([5,4,6,2,1,3]), Vecsmall([4,6,5,1,3,2])]] ? [[permorder(c[1]),#c] | c <- S ] %4 = [[1,1], [3,2], [2,3]]
This command also accepts subgroups returned by galoissubgroups
:
? subs = galoissubgroups(G); H = subs[5]; ? galoisidentify(H) %2 = [2, 1] \\ Z/2 ? S = galoisconjclasses(subgroups_ofG[5]); ? [[permorder(c[1]),#c] | c <- S ] %4 = [[1,1], [2,1]]
The library syntax is GEN galoisconjclasses(GEN gal)
.
gal being be a Galois group as output by galoisinit
,
export the underlying permutation group as a string suitable
for (no flags or flag = 0) GAP or (flag = 1) Magma. The following example
compute the index of the underlying abstract group in the GAP library:
? G = galoisinit(x^6+108); ? s = galoisexport(G) %2 = "Group((1, 2, 3)(4, 5, 6), (1, 4)(2, 6)(3, 5))" ? extern("echo \"IdGroup("s");\" | gap -q") %3 = [6, 1] ? galoisidentify(G) %4 = [6, 1]
This command also accepts subgroups returned by galoissubgroups
.
To import a GAP permutation into gp (for galoissubfields
for
instance), the following GAP function may be useful:
PermToGP := function(p, n) return Permuted([1..n],p); end; gap> p:= (1,26)(2,5)(3,17)(4,32)(6,9)(7,11)(8,24)(10,13)(12,15)(14,27) (16,22)(18,28)(19,20)(21,29)(23,31)(25,30) gap> PermToGP(p,32); [ 26, 5, 17, 32, 2, 9, 11, 24, 6, 13, 7, 15, 10, 27, 12, 22, 3, 28, 20, 19, 29, 16, 31, 8, 30, 1, 14, 18, 21, 25, 23, 4 ]
The library syntax is GEN galoisexport(GEN gal, long flag)
.
gal being be a Galois group as output by galoisinit
and
perm an element of gal.group, a vector of such elements
or a subgroup of gal as returned by galoissubgroups,
computes the fixed field of gal by the automorphism defined by the
permutations perm of the roots gal.roots. P is guaranteed to
be squarefree modulo gal.p.
If no flags or flag = 0, output format is the same as for nfsubfield
,
returning [P,x] such that P is a polynomial defining the fixed field, and
x is a root of P expressed as a polmod in gal.pol.
If flag = 1 return only the polynomial P.
If flag = 2 return [P,x,F] where P and x are as above and F is the factorization of gal.pol over the field defined by P, where variable v (y by default) stands for a root of P. The priority of v must be less than the priority of the variable of gal.pol (see Section se:priority). In this case, P is also expressed in the variable v for compatibility with F. Example:
? G = galoisinit(x^4+1); ? galoisfixedfield(G,G.group[2],2) %2 = [y^2 - 2, Mod(- x^3 + x, x^4 + 1), [x^2 - y*x + 1, x^2 + y*x + 1]]
computes the factorization x4+1 = (x2-sqrt{2}x+1)(x2+sqrt{2}x+1)
The library syntax is GEN galoisfixedfield(GEN gal, GEN perm, long flag, long v = -1)
where v
is a variable number.
Query the galpol
package for a group of order a with index b
in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina Eick and
Eamonn O'Brien.
The current version of galpol
supports groups of order a ≤ 143.
If b is omitted, return the number of isomorphism classes of
groups of order a.
The library syntax is GEN galoisgetgroup(long a, long b)
.
Also available is GEN galoisnbpol(long a)
when b
is omitted.
Query the galpol
package for a string describing the group of order
a with index b in the GAP4 Small Group library, by Hans Ulrich Besche,
Bettina Eick and Eamonn O'Brien.
The strings were generated using the GAP4 function StructureDescription
.
The command below outputs the names of all abstract groups of order 12:
? o = 12; N = galoisgetgroup(o); \\ # of abstract groups of order 12 ? for(i=1, N, print(i, ". ", galoisgetname(o,i))) 1. C3 : C4 2. C12 3. A4 4. D12 5. C6 x C2
The current version of galpol
supports groups of order a ≤ 143.
For a ≥ 16, it is possible for different groups to have the same name:
? o = 20; N = galoisgetgroup(o); ? for(i=1, N, print(i, ". ", galoisgetname(o,i))) 1. C5 : C4 2. C20 3. C5 : C4 4. D20 5. C10 x C2
The library syntax is GEN galoisgetname(long a, long b)
.
Query the galpol
package for a polynomial with Galois group
isomorphic to
GAP4(a,b), totally real if s = 1 (default) and totally complex if s = 2.
The current version of galpol
supports groups of order a ≤ 143.
The output is a vector [pol
, den
] where
* pol
is the polynomial of degree a
* den
is the denominator of nfgaloisconj(pol)
.
Pass it as an optional argument to galoisinit
or nfgaloisconj
to
speed them up:
? [pol,den] = galoisgetpol(64,4,1); ? G = galoisinit(pol); time = 352ms ? galoisinit(pol, den); \\ passing 'den' speeds up the computation time = 264ms ? % == %` %4 = 1 \\ same answer
If b and s are omitted, return the number of isomorphism classes of groups of order a.
The library syntax is GEN galoisgetpol(long a, long b, long s)
.
Also available is GEN galoisnbpol(long a)
when b and s
are omitted.
gal being be a Galois group as output by galoisinit
,
output the isomorphism class of the underlying abstract group as a
two-components vector [o,i], where o is the group order, and i is the
group index in the GAP4 Small Group library, by Hans Ulrich Besche, Bettina
Eick and Eamonn O'Brien.
This command also accepts subgroups returned by galoissubgroups
.
The current implementation is limited to degree less or equal to 127. Some larger "easy" orders are also supported.
The output is similar to the output of the function IdGroup
in GAP4.
Note that GAP4 IdGroup
handles all groups of order less than 2000
except 1024, so you can use galoisexport
and GAP4 to identify large
Galois groups.
The library syntax is GEN galoisidentify(GEN gal)
.
Computes the Galois group
and all necessary information for computing the fixed fields of the
Galois extension K/ℚ where K is the number field defined by
pol (monic irreducible polynomial in ℤ[X] or
a number field as output by nfinit
). The extension K/ℚ must be
Galois with Galois group "weakly" super-solvable, see below;
returns 0 otherwise. Hence this permits to quickly check whether a polynomial
of order strictly less than 48 is Galois or not.
The algorithm used is an improved version of the paper "An efficient algorithm for the computation of Galois automorphisms", Bill Allombert, Math. Comp, vol. 73, 245, 2001, pp. 359–375.
A group G is said to be "weakly" super-solvable if there exists a normal series
{1} = H0 ◃ H1 ◃ ... ◃ Hn-1 ◃ Hn
such that each Hi is normal in G and for i < n, each quotient group
Hi+1/Hi is cyclic, and either Hn = G (then G is super-solvable) or
G/Hn is isomorphic to either A4, S4 or the group
(3 x 3):4 (GAP4(36,9)
).
In practice, almost all small groups are WKSS, the exceptions having order 48(2), 56(1), 60(1), 72(3), 75(1), 80(1), 96(10), 112(1), 120(3) and ≥ 144.
This function is a prerequisite for most of the galois
xxx routines.
For instance:
P = x^6 + 108; G = galoisinit(P); L = galoissubgroups(G); vector(#L, i, galoisisabelian(L[i],1)) vector(#L, i, galoisidentify(L[i]))
The output is an 8-component vector gal.
gal[1] contains the polynomial pol
(gal.pol
).
gal[2] is a three-components vector [p,e,q] where p is a
prime number (gal.p
) such that pol totally split
modulo p , e is an integer and q = pe (gal.mod
) is the
modulus of the roots in gal.roots
.
gal[3] is a vector L containing the p-adic roots of
pol as integers implicitly modulo gal.mod
.
(gal.roots
).
gal[4] is the inverse of the Vandermonde matrix of the p-adic roots of pol, multiplied by gal[5].
gal[5] is a multiple of the least common denominator of the automorphisms expressed as polynomial in a root of pol.
gal[6] is the Galois group G expressed as a vector of
permutations of L (gal.group
).
gal[7] is a generating subset S = [s1,...,sg] of G
expressed as a vector of permutations of L (gal.gen
).
gal[8] contains the relative orders [o1,...,og] of
the generators of S (gal.orders
).
Let Hn be as above, we have the following properties:
* if G/Hn ~ A4 then [o1,...,og] ends by [2,2,3].
* if G/Hn ~ S4 then [o1,...,og] ends by [2,2,3,2].
* if G/Hn ~ (3 x 3):4 (GAP4(36,9)
) then
[o1,...,og] ends by [3,3,4].
* for 1 ≤ i ≤ g the subgroup of G generated by [s1,...,si] is normal, with the exception of i = g-2 in the A4 and (3 x 3):4 cases and of i = g-3 in the S4 case.
* the relative order oi of si is its order in the
quotient group G/<
s1,...,si-1>
, with the same
exceptions.
* for any x ∈ G there exists a unique family [e1,...,eg] such that (no exceptions):
-- for 1 ≤ i ≤ g we have 0 ≤ ei < oi
-- x = g1e1g2e2...gnen
If present den must be a suitable value for gal[5].
The library syntax is GEN galoisinit(GEN pol, GEN den = NULL)
.
gal being as output by galoisinit
, return 0 if
gal is not an abelian group, and the HNF matrix of gal over
gal.gen
if flag = 0, 1 if flag = 1, and the SNF matrix of gal
if flag = 2.
This command also accepts subgroups returned by galoissubgroups
.
The library syntax is GEN galoisisabelian(GEN gal, long flag)
.
gal being as output by galoisinit
, and subgrp a subgroup
of gal as output by galoissubgroups
,return 1 if subgrp is a
normal subgroup of gal, else return 0.
This command also accepts subgroups returned by galoissubgroups
.
The library syntax is long galoisisnormal(GEN gal, GEN subgrp)
.
gal being a
Galois group as output by galoisinit
and perm a element of
gal.group, return the polynomial defining the Galois
automorphism, as output by nfgaloisconj
, attached to the
permutation perm of the roots gal.roots. perm can
also be a vector or matrix, in this case, galoispermtopol
is
applied to all components recursively.
Note that
G = galoisinit(pol); galoispermtopol(G, G[6])~
is equivalent to nfgaloisconj(pol)
, if degree of pol is greater
or equal to 2.
The library syntax is GEN galoispermtopol(GEN gal, GEN perm)
.
Compute the Galois group over Q of the splitting field of P, that is the smallest field over which P is totally split. P is assumed to be integral, monic and irreducible; it can also be given by a nf
structure. If d is given, it must be a multiple of
the splitting field degree. The output is compatible with functions expecting
a galoisinit
structure.
The library syntax is GEN galoissplittinginit(GEN P, GEN d = NULL)
.
Computes the subextension L of ℚ(ζn) fixed by the subgroup H ⊂ (ℤ/nℤ)*. By the Kronecker-Weber theorem, all abelian number fields can be generated in this way (uniquely if n is taken to be minimal). This function output is somewhat canonical, as it returns the minimal polynomial of a Gaussian period Trℚ(ζ_{n)/L}(ζn).
The pair (n, H) is deduced from the parameters (N, H) as follows
* N an integer: then n = N; H is a generator, i.e. an integer or an integer modulo n; or a vector of generators.
* N the output of znstar
(n) or znstar
(n,1).
H as in the first case above, or a matrix, taken to be a HNF left divisor
of the SNF for (ℤ/nℤ)*
(N.cyc
), giving the generators of H in terms of N.gen
.
* N the output of bnrinit(bnfinit(y), m)
where m is a
module. H as in the first case, or a matrix taken to be a HNF left
divisor of the SNF for the ray class group modulo m
(of type N.cyc
), giving the generators of H in terms of
N.bid.gen
( = N
.gen if N includes generators).
In this last case, beware that H is understood relatively to N; in particular, if the infinite place does not divide the module, e.g if m is an integer, then it is not a subgroup of (ℤ/nℤ)*, but of its quotient by {± 1}.
If flag = 0, computes a polynomial (in the variable v) defining the subfield of ℚ(ζn) fixed by the subgroup H of (ℤ/nℤ)*.
If flag = 1, computes only the conductor of the abelian extension, as a module.
If flag = 2, outputs [pol, N], where pol is the polynomial as output when flag = 0 and N the conductor as output when flag = 1.
If flag = 3; outputs galoisinit(pol)
.
The following function can be used to compute all subfields of
ℚ(ζn) (of exact degree d
, if d
is set):
subcyclo(n, d = -1)= { my(bnr,L,IndexBound); IndexBound = if (d < 0, n, [d]); bnr = bnrinit(bnfinit(y), [n,[1]]); L = subgrouplist(bnr, IndexBound, 1); vector(#L,i, galoissubcyclo(bnr,L[i])); }
Setting L = subgrouplist(bnr, IndexBound)
would produce subfields of
exact conductor n oo .
The library syntax is GEN galoissubcyclo(GEN N, GEN H = NULL, long flag, long v = -1)
where v
is a variable number.
Outputs all the subfields of the Galois group G, as a vector.
This works by applying galoisfixedfield
to all subgroups. The meaning of
flag is the same as for galoisfixedfield
.
The library syntax is GEN galoissubfields(GEN G, long flag, long v = -1)
where v
is a variable number.
Outputs all the subgroups of the Galois group gal
. A subgroup is a
vector [gen, orders], with the same meaning
as for gal.gen and gal.orders. Hence gen is a vector of
permutations generating the subgroup, and orders is the relatives
orders of the generators. The cardinality of a subgroup is the product of the
relative orders. Such subgroup can be used instead of a Galois group in the
following command: galoisisabelian
, galoissubgroups
,
galoisexport
and galoisidentify
.
To get the subfield fixed by a subgroup sub of gal, use
galoisfixedfield(gal,sub[1])
The library syntax is GEN galoissubgroups(GEN G)
.
gc being the structure returned by gcharinit
, returns a t_MAT
whose columns form a basis of the subgroup of algebraic Grossencharacters in
gc (Weil type A0). The last component is interpreted as a power of the
norm.
If type is a t_VEC
of length gc.r1
+gc.r2
,
containing a pair of integers [pτ,qτ] for each complex
embedding τ, returns a t_VEC
containing a character whose infinity type
at τ is
z ⟼
z-pτz-qτ
if such a character exists, or empty otherwise.
The full set of characters of that infinity type is obtained by multiplying by
the group of finite order characters.
? bnf = bnfinit(x^4-2*x^3+23*x^2-22*x+6,1); ? gc = gcharinit(bnf,1); ? gc.cyc % = [6, 0, 0, 0, 0.E-57] ? gcharalgebraic(gc) % = [1 0 0 0] [0 1 0 0] [0 0 1 0] [0 0 0 0] [0 0 -1/2 -1] ? gcharalgebraic(gc,[[1,1],[0,1]]) % = [] \\ pτ+qτ must be constant for an algebraic character to exist ? chi = gcharalgebraic(gc,[[1,1],[0,2]])[1] % = [0, 1, 2, 0, -1]~ ? for(i=0,5,print(lfuneuler([gc,chi+[i,0,0,0,0]~],3))); \\ all characters with this infinity type: multiply by finite order characters
When the torsion subgroup is not cyclic, we can enumerate the characters of a
given type with forvec
.
? bnf = bnfinit(x^4+15*x^2+45,1); ? gc = gcharinit(bnf,1); ? gc.cyc % = [2, 2, 0, 0, 0, 0.E-57] ? [chi] = gcharalgebraic(gc,[[2,0],[2,0]]); ? {forvec(v=vectorv(2,i,[0,gc.cyc[i]-1]), print(round(lfunan([gc,chi+concat(v,[0,0,0,0]~)],20))); )}; [1, 0, 0, 4, -5, 0, 0, 0, -9, 0, 16, 0, 0, 0, 0, 16, 0, 0, 16, -20] [1, 0, 0, -4, 5, 0, 0, 0, 9, 0, 16, 0, 0, 0, 0, 16, 0, 0, -16, -20] [1, 0, 0, 4, 5, 0, 0, 0, 9, 0, -16, 0, 0, 0, 0, 16, 0, 0, 16, 20] [1, 0, 0, -4, -5, 0, 0, 0, -9, 0, -16, 0, 0, 0, 0, 16, 0, 0, -16, 20]
Some algebraic Hecke characters are related to CM Abelian varieties. We first show an example with an elliptic curve.
? E = ellinit([0, 0, 1, -270, -1708]); \\ elliptic curve with potential CM by ℚ(sqrt{-3}) ? bnf = bnfinit(x^2+3,1); ? p3 = idealprimedec(bnf,3)[1]; ? gc = gcharinit(bnf,Mat([p3,2])); ? gc.cyc % = [0, 0.E-57] ? [chi] = gcharalgebraic(gc,[[1,0]]) % = [[-1, -1/2]~] ? LE = lfuncreate(E); ? lfunan(LE,20) % = [1, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 5, 0, 0, 4, 0, 0, -7, 0] ? Lchi = lfuncreate([gc,chi]); ? round(lfunan(Lchi,20)) % = [1, 0, 0, -2, 0, 0, -1, 0, 0, 0, 0, 0, 5, 0, 0, 4, 0, 0, -7, 0]
Here is an example with a CM Abelian surface.
? L = lfungenus2([-2*x^4 - 2*x^3 + 2*x^2 + 3*x - 2, x^3]); ? bnf = bnfinit(a^4 - a^3 + 2*a^2 + 4*a + 3, 1); ? pr = idealprimedec(bnf,13)[1]; ? gc = gcharinit(bnf,pr); ? gc.cyc % = [3, 0, 0, 0, 0.E-57] ? chitors = [1,0,0,0,0]~; ? typ = [[1,0],[1,0]]; ? [chi0] = gcharalgebraic(gc,typ); ? igood = oo; nbgood = 0; ? {for(i=0,gc.cyc[1]-1, chi = chi0 + i*chitors; Lchi = lfuncreate([gc,chi]); if(lfunparams(L) == lfunparams(Lchi) && exponent(lfunan(L,10) - lfunan(Lchi,10)) < -50, igood=i; nbgood++ ); )}; ? nbgood % = 1 ? chi = chi0 + igood*chitors; ? Lchi = lfuncreate([gc,chi]); ? lfunan(L,30) % = [1, 0, -3, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, -3, 0] ? round(lfunan(Lchi,30)) % = [1, 0, -3, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, -3, 0]
The library syntax is GEN gcharalgebraic(GEN gc, GEN type = NULL)
.
Returns the conductor of chi
, as a modulus over gc.bnf
. This is
the minimum modulus 𝔪 such that
U(𝔪) ⊂ ker(chi)
indicating the exact ramification of chi.
* for a real place v, v | 𝔪 iff χv(-1) = -1.
* for a finite place 𝔭, the prime power 𝔭e divides exactly 𝔪 if e ≥ 0 is the smallest integer such that χ𝔭 (Ue) = 1 where U0 = ℤ𝔭× and Ui = 1+𝔭iℤ𝔭 for i > 0.
? bnf = bnfinit(x^2-5,1); ? gc = gcharinit(bnf,[(13*19)^2,[1,1]]); ? gc.cyc % = [8892, 6, 2, 0, 0.E-57] ? chi = [0,0,1,1]~; ? gcharconductor(gc,chi) % = [[61009, 7267; 0, 169], [1, 0]] ? gcharconductor(gc,13*chi) % = [[4693, 559; 0, 13], [1, 0]] ? gcharconductor(gc,13*19*chi) % = [[247, 65; 0, 13], [1, 0]] ? gcharconductor(gc,13*19*168*chi) % = [[19, 5; 0, 1], [0, 0]]
The library syntax is GEN gchar_conductor(GEN gc, GEN chi)
.
Returns internal logarithm vector of character chi
as a t_VEC
in ℝn, so that for all x,
gchareval
(gc,chi,x,0) is equal to
gcharduallog
(gc,chi) * gcharlog
(gc,x) in
ℝ/ ℤ.
The components are organized as follows:
* the first ns
components are in ℝ and describe the character on
the class group generators: θ encodes 𝔭 ⟼
exp(2iπθ),
* the next nc
components are in ℝ and describe the idealstar
group character via its image on generators: θ encodes the
image exp(2iπθ),
* the next r1+r2 components are in ℝ and correspond to characters
of ℝ for each infinite place: ϕ encodes x ⟼
|x|iϕ in
the real case and z ⟼
|z|2iϕ in the complex case,
* the last r2 components are in ℤ and correspond to characters of
ℝ/ℤ for each complex place: k encodes z ⟼
(z/|z|)k.
* the last component s is in ℂ and corresponds to a power |.|s of the adélic norm.
See also gcharlog
.
? bnf = bnfinit(x^3+4*x-1,1); ? gc = gcharinit(bnf,[1,[1]]); ? gc.cyc % = [2, 0, 0, 0.E-57] ? chi = [0,1,0]~; ? f = gcharduallog(gc,chi) % = [0.153497221319231, 1/2, 0.776369647248353, -0.388184823624176, 1, 0] ? pr = idealprimedec(bnf,2)[1]; ? v = gcharlog(gc,pr); ? exp(2*I*Pi*f*v) % = -0.569867696226731232993110144 - 0.821736459454756074068598760*I ? gchareval(gc,chi,pr) % = -0.569867696226731232993110144 - 0.821736459454756074068598760*I
The library syntax is GEN gcharduallog(GEN gc, GEN chi)
.
gc being the structure returned by gcharinit
, chi a
character in gc, and x an ideal of the base field, returns the
value χ(x). If flag = 1 (default), returns a value in ℂ×;
if flag = 0, returns a value in ℂ/ℤ, normalized so that the real part is
between -1/2 and 1/2.
? bnf = bnfinit(x^2-5); ? gc = gcharinit(bnf,1); ? chi = [1]~; ? pr = idealprimedec(bnf,11)[1]; ? a = gchareval(gc,chi,pr) % = -0.3804107379142448929315340886 - 0.9248176417432464199580504588*I ? b = gchareval(gc,chi,pr,0) % = -0.3121086861831031476247589216 ? a == exp(2*Pi*I*b) %7 = 1
The library syntax is GEN gchareval(GEN gc, GEN chi, GEN x, long flag)
.
gc being a Grossencharacter group as output by gcharinit
, Lv
being t_VEC
of places v encoded by a t_INT
(infinite place) or a prime
ideal structure representing a prime not dividing the modulus of gc (finite
place), and Lchiv being a t_VEC
of local characters χv encoded
by [k,ϕ] with k a t_INT
and ϕ a t_REAL
or
t_COMPLEX
representing x ⟼
sign(x)k|x|iϕ (real
place) or z ⟼
(z/|z|)k|z|2iϕ(complex place) or by a t_REAL
or t_COMPLEX
θ representing 𝔭 ⟼
exp(2iπ θ)
(finite place), returns a Grossencharacter ψ belonging to g such
that ψv ~ χv for all v.
At finite places, in place of a scalar one can provide a t_VEC
whose
last component is θ, as output by gcharlocal
.
To ensure proper identification, it is recommended to provide all infinite
places together with a set of primes that generate the ray class group of
modulus gc.mod
.
? bnf = bnfinit(x^2-5,1); ? gc = gcharinit(bnf,1); ? chi = gcharidentify(gc,[2],[[0,13.]]); ? gcharlocal(gc,chi,2) % = [0, 13.057005210545987626926134713745179631] ? pr = idealprimedec(bnf,11)[1]; ? chi = gcharidentify(gc,[pr],[0.3]); ? gchareval(gc,chi,pr,0) % = 0.30000006229129706787363344444425752636
If you know only few digits, it may be a good idea to reduce the current precision to obtain a meaningful result.
? bnf = bnfinit(x^2-5,1); ? gc = gcharinit(bnf,1); ? pr = idealprimedec(bnf,11)[1]; ? chi = gcharidentify(gc,[pr],[0.184760]) % = [-420226]~ \\ unlikely to be meaningful ? gchareval(gc,chi,pr,0) % = 0.18475998070331376194260927294721168954 ? \p 10 realprecision = 19 significant digits (10 digits displayed) ? chi = gcharidentify(gc,[pr],[0.184760]) % = [-7]~ \\ probably what we were looking for ? gchareval(gc,chi,pr,0) % = 0.1847608033 ? \p 38 realprecision = 38 significant digits ? gchareval(gc,chi,pr,0) % = 0.18476080328172203337331245154966763237
The output may be a quasi-character.
? bnf = bnfinit(x^2-2,1); ? gc = gcharinit(bnf,1); gc.cyc % = [0, 0.E-57] ? gcharidentify(gc,[1,2],[[0,3.5+1/3*I],[0,-3.5+1/3*I]]) % = [-1, 1/3]~
The library syntax is GEN gchar_identify(GEN gc, GEN Lv, GEN Lchiv, long prec)
.
bnf being a number field output by bnfinit
(including
fundamental units), f a modulus, initializes a structure (gc
)
describing the group of Hecke Grossencharacters of modulus f.
(As in idealstar
, the finite part of the conductor may be given
by a factorization into prime ideals, as produced by idealfactor
.)
The following member functions are available
on the result: .bnf
is the underlying bnf,
.mod
the modulus, .cyc
its elementary divisors.
The internal representation uses a logarithm map on ideals
ℒ: I → ℝn,
so that a Hecke Grossencharacter χ can be described by a n
components vector v via
χ: a ∈ I ⟼
exp(2iπ v.{ℒ(a)}).
See gcharlog
for more details on the map ℒ.
? bnf = bnfinit(polcyclo(5),1); \\ initializes number field ℚ(ζ5) ? pr = idealprimedec(bnf,5)[1]; \\ prime 𝔭 = (1-ζ5) above 5 ? gc = gcharinit(bnf,idealpow(bnf,pr,2)); \\ characters of modulus dividing 𝔭2 ? gc.cyc \\ structure as an abelian group % = [0,0,0,0.E-57] ? chi = [1,1,-1,0]~; \\ a character ? gcharconductor(gc,chi)[1] % = [5 4 1 4] [0 1 0 0] [0 0 1 0] [0 0 0 1]
Currently, gc
is a row vector with 11 components:
gc[1] is a matrix whose rows describe a system of generators of the characters as vectors of ℝn, under the above description.
gc[2] contains the underlying number field bnf
(gc.bnf
).
gc[3] contains the underlying number field nf
(gc.nf
), possibly stored at higher precision than bnf.
gc[4] contains data for computing in (ℤK/f)×.
gc[5] is a vector S of prime ideals which generate the class group.
gc[6] contains data to compute discrete logarithms with respect to S in the class group.
gc[7] is a vector [Sunits,m]
, where Sunits
describes
the S-units of bnf and m is a relation matrix for internal usage.
gc[8] is
[Vecsmall([evalprec,prec,nfprec]), Vecsmall([ntors,nfree,nalg])]
caching precisions and various dimensions.
gc[9] is a vector describing gc as a ℤ-module
via its SNF invariants (gc.cyc
), the last component
representing the norm character.
gc[10] is a vector [R,U,Ui]
allowing to convert characters
from SNF basis to internal combination of generators.
Specifically, a character chi
in SNF basis has coordinates
chi*Ui
in internal basis (the rows of gc[1]).
gc[11] = m is the matrix of ℒ(v) for all S-units v.
gc[12] = u is an integral base change matrix such that gc[1] corresponds to (mu)-1.
The library syntax is GEN gcharinit(GEN bnf, GEN f, long prec)
.
gc being the structure returned by gcharinit
and chi
a character on gc, returns 1 if and only if chi is an algebraic
(Weil type A0) character, so that its infinity type at every complex
embedding τ can be written
z ⟼
z-pτz-qτ
for some pair of integers (pτ,qτ).
If type is given, it is set to the t_VEC
of exponents
[pτ,qτ].
? bnf = bnfinit(x^4+1,1); ? gc = gcharinit(bnf,1); ? gc.cyc % = [0, 0, 0, 0.E-57] ? chi1 = [0,0,1]~; ? gcharisalgebraic(gc,chi1) % = 0 ? gcharlocal(gc,chi1,1) % = [-3, -0.89110698909568455588720672648627467040] ? chi2 = [1,0,0,-3]~; ? gcharisalgebraic(gc,chi2,&typ) % = 1 ? typ % = [[6, 0], [2, 4]] ? gcharlocal(gc,chi2,1) % = [-6, 3*I]
The library syntax is GEN gcharisalgebraic(GEN gc, GEN chi, GEN *type = NULL)
.
gc
being a gchar structure initialised by gcharinit
, returns
the local component χv, where v is either an integer between 1
and r1+r2 encoding an infinite place, or a prime ideal structure
encoding a finite place.
* if v is a real place, χv(x) = {\rm sign}(x)k |x|iϕ is encoded as [k,ϕ];
* if v is a complex place, χv(z) = (z/|z|)k |z|2iϕ is encoded as [k,ϕ];
* if v = 𝔭 is a finite place not dividing gc.mod
,
χv(πv) = exp(2iπ θ) is encoded as [θ];
* if v = 𝔭 is a finite place dividing gc.mod
,
we can define a bid structure attached to the multiplicative group
G = (ℤK/𝔭k)*, where 𝔭k divides exactly
gc.mod
(see idealstar
).
Then χv is encoded as [c1,...,cn,θ]
where [c1,...,cn] defines a character on G
(see gchareval
) and χv(πv) = exp(2iπθ).
This bid structure only depends on gc
and v
(and not on the character χ);
it can be recovered through the optional argument BID.
? bnf = bnfinit(x^3-x-1); ? gc = gcharinit(bnf,1); ? gc.cyc % = [0, 0, 0.E-57] ? chi = [0,1,1/3]~; ? pr = idealprimedec(bnf,5)[1]; ? gcharlocal(gc,chi,1) % = [0, -4.8839310048284836274074581373242545693 - 1/3*I] ? gcharlocal(gc,chi,2) % = [6, 2.4419655024142418137037290686621272847 - 1/3*I] ? gcharlocal(gc,chi,pr) % = [0.115465135184293124024408915 + 0.0853833331211293579127218326*I] ? bnf = bnfinit(x^2+1,1); ? pr3 = idealprimedec(bnf,3)[1]; ? pr5 = idealprimedec(bnf,5)[1]; ? gc = gcharinit(bnf,[pr3,2;pr5,3]); ? gc.cyc % = [600, 3, 0, 0.E-57] ? chi = [1,1,1]~; ? gcharlocal(gc,chi,pr3,&bid) % = [1, 1, -21/50] ? bid.cyc % = [24, 3] ? gcharlocal(gc,chi,pr5,&bid) % = [98, -0.30120819117478336291229946188762973702] ? bid.cyc % = [100]
The library syntax is GEN gcharlocal(GEN gc, GEN chi, GEN v, long prec, GEN *BID = NULL)
.
Returns the internal (logarithmic) representation of the ideal x suitable
for computations in gc, as a t_COL
in ℝn.
Its n = ns+nc
+(r1+r2)+r2+1 components correspond to a
logarithm map on the group of fractional ideals ℒ: I → ℝn, see
gcharinit
.
More precisely, let x = (α) ∏ 𝔭iai a
principalization of x on a set S of primes generating
the class group (see bnfisprincipal
),
then the logarithm of x is the t_COL
ℒ(x) = [ (ai), logf(α), (log|x/α|τ)/(2π), (arg(x/α)τ)/(2π), (log N(x))/(2π).i ]
where
* the exponent vector (ai) has ns
components, where
ns
= #S is the number of prime ideals used to generate the class group,
* logf(α) is a discrete logarithm of
α in the idealstar
group (ℤK/f)×,
with nc
components,
* log|x/α|τ has r1+r2 components, one for each real embedding and pair of complex embeddings τ: K → ℂ (and |z|τ = |z|2 for complex τ).
* arg{(x/α)τ} has r2 components, one for each pair of complex embeddings τ: K → ℂ.
* N(x) is the norm of the ideal x.
? bnf = bnfinit(x^3-x^2+5*x+1,1); ? gc = gcharinit(bnf,3); ? gc.cyc % = [3, 0, 0, 0.E-57] ? chi = [1,1,0,-1]~; ? f = gcharduallog(gc,chi); ? pr = idealprimedec(bnf,5)[1]; ? v = gcharlog(gc,pr) % = [2, -5, -1, 0.0188115475004995312411, -0.0188115475004995312411, -0.840176314833856764413, 0.256149999363388073738*I]~ ? exp(2*I*Pi*f*v) % = -4.5285995080704456583673312 + 2.1193835177957097598574507*I ? gchareval(gc,chi,pr) % = -4.5285995080704456583673312 + 2.1193835177957097598574507*I
The library syntax is GEN gcharlog(GEN gc, GEN x, long prec)
.
gc being a Grossencharacter group output by gcharinit
,
recomputes its archimedean components ensuring accurate computations to
current precision.
It is advisable to increase the precision before computing several values at large ideals.
The library syntax is GEN gcharnewprec(GEN gc, long prec)
.
Sum of the two ideals x and y in the number field nf. The result is given in HNF.
? K = nfinit(x^2 + 1); ? a = idealadd(K, 2, x + 1) \\ ideal generated by 2 and 1+I %2 = [2 1] [0 1] ? pr = idealprimedec(K, 5)[1]; \\ a prime ideal above 5 ? idealadd(K, a, pr) \\ coprime, as expected %4 = [1 0] [0 1]
This function cannot be used to add arbitrary ℤ-modules, since it assumes that its arguments are ideals:
? b = Mat([1,0]~); ? idealadd(K, b, b) \\ only square t_MATs represent ideals *** idealadd: nonsquare t_MAT in idealtyp. ? c = [2, 0; 2, 0]; idealadd(K, c, c) \\ nonsense %6 = [2 0] [0 2] ? d = [1, 0; 0, 2]; idealadd(K, d, d) \\ nonsense %7 = [1 0] [0 1]
In the last two examples, we get wrong results since the
matrices c and d do not correspond to an ideal: the ℤ-span of their
columns (as usual interpreted as coordinates with respect to the integer basis
K.zk
) is not an ℤK-module. To add arbitrary ℤ-modules generated
by the columns of matrices A and B, use mathnf(concat(A,B))
.
The library syntax is GEN idealadd(GEN nf, GEN x, GEN y)
.
x and y being two co-prime integral ideals (given in any form), this gives a two-component row vector [a,b] such that a ∈ x, b ∈ y and a+b = 1.
The alternative syntax idealaddtoone
(nf,v), is supported, where
v is a k-component vector of ideals (given in any form) which sum to
ℤK. This outputs a k-component vector e such that e[i] ∈ x[i] for
1 ≤ i ≤ k and ∑1 ≤ i ≤ ke[i] = 1.
The library syntax is GEN idealaddtoone0(GEN nf, GEN x, GEN y = NULL)
.
If x is a fractional ideal (given in any form), gives an element α in nf such that for all prime ideals 𝔭 such that the valuation of x at 𝔭 is nonzero, we have v𝔭(α) = v𝔭(x), and v𝔭(α) ≥ 0 for all other 𝔭.
The argument x may also be given as a prime ideal factorization, as
output by idealfactor
, but allowing zero exponents.
This yields an element α such that for all prime ideals 𝔭
occurring in x, v𝔭(α) = v𝔭(x);
for all other prime ideals, v𝔭(α) ≥ 0.
flag is deprecated (ignored), kept for backward compatibility.
The library syntax is GEN idealappr0(GEN nf, GEN x, long flag)
.
Use directly GEN idealappr(GEN nf, GEN x)
since flag is ignored.
x being a prime ideal factorization (i.e. a 2-columns matrix whose first column contains prime ideals and the second column contains integral exponents), y a vector of elements in nf indexed by the ideals in x, computes an element b such that
v𝔭(b - y𝔭) ≥ v𝔭(x) for all prime ideals in x and v𝔭(b) ≥ 0 for all other 𝔭.
? K = nfinit(t^2-2); ? x = idealfactor(K, 2^2*3) %2 = [[2, [0, 1]~, 2, 1, [0, 2; 1, 0]] 4] [ [3, [3, 0]~, 1, 2, 1] 1] ? y = [t,1]; ? idealchinese(K, x, y) %4 = [4, -3]~
The argument x may also be of the form [x, s] where the first component
is as above and s is a vector of signs, with r1 components
si in {-1,0,1}:
if σi denotes the i-th real embedding of the number field,
the element b returned satisfies further
sign
(σi(b)) = si for all i such that si = ±1.
In other words, the sign is fixed to si at the i-th embedding whenever
si is nonzero.
? idealchinese(K, [x, [1,1]], y) %5 = [16, -3]~ ? idealchinese(K, [x, [-1,-1]], y) %6 = [-20, -3]~ ? idealchinese(K, [x, [1,-1]], y) %7 = [4, -3]~
If y is omitted, return a data structure which can be used in place of x in later calls and allows to solve many chinese remainder problems for a given x more efficiently. In this case, the right hand side y is not allowed to have denominators, unless they are coprime to x.
? C = idealchinese(K, [x, [1,1]]); ? idealchinese(K, C, y) \\ as above %9 = [16, -3]~ ? for(i=1,10^4, idealchinese(K,C,y)) \\ ... but faster ! time = 80 ms. ? for(i=1,10^4, idealchinese(K,[x,[1,1]],y)) time = 224 ms.
Finally, this structure is itself allowed in place of x, the new s overriding the one already present in the structure. This allows to initialize for different sign conditions more efficiently when the underlying ideal factorization remains the same.
? D = idealchinese(K, [C, [1,-1]]); \\ replaces [1,1] ? idealchinese(K, D, y) %13 = [4, -3]~ ? for(i=1,10^4,idealchinese(K,[C,[1,-1]])) time = 40 ms. \\ faster than starting from scratch ? for(i=1,10^4,idealchinese(K,[x,[1,-1]])) time = 128 ms.
The library syntax is GEN idealchinese(GEN nf, GEN x, GEN y = NULL)
.
Also available is
GEN idealchineseinit(GEN nf, GEN x)
when y = NULL
.
Given two integral ideals x and y in the number field nf, returns a β in the field, such that β.x is an integral ideal coprime to y. In fact, β is also guaranteed to be integral outside primes dividing y.
The library syntax is GEN idealcoprime(GEN nf, GEN x, GEN y)
.
Quotient x.y-1 of the two ideals x and y in the number field nf. The result is given in HNF.
If flag is nonzero, the quotient x.y-1 is assumed to be an integral ideal. This can be much faster when the norm of the quotient is small even though the norms of x and y are large. More precisely, the algorithm cheaply removes all maximal ideals above rational primes such that vp(Nx) = vp(Ny).
The library syntax is GEN idealdiv0(GEN nf, GEN x, GEN y, long flag)
.
Also available are GEN idealdiv(GEN nf, GEN x, GEN y)
(flag = 0) and GEN idealdivexact(GEN nf, GEN x, GEN y)
(flag = 1).
Let nf be a number field as output by nfinit
, and x a
fractional ideal. This function returns the nonnegative rational generator
of x ∩ ℚ. If x is an extended ideal, the extended part is ignored.
? nf = nfinit(y^2+1); ? idealdown(nf, -1/2) %2 = 1/2 ? idealdown(nf, (y+1)/3) %3 = 2/3 ? idealdown(nf, [2, 11]~) %4 = 125 ? x = idealprimedec(nf, 2)[1]; idealdown(nf, x) %5 = 2 ? idealdown(nf, [130, 94; 0, 2]) %6 = 130
The library syntax is GEN idealdown(GEN nf, GEN x)
.
Factors into prime ideal powers the ideal x in the number field
nf. The output format is similar to the factor
function, and
the prime ideals are represented in the form output by the
idealprimedec
function. If lim is set, return partial
factorization, including only prime ideals above rational primes
< lim.
? nf = nfinit(x^3-2); ? idealfactor(nf, x) \\ a prime ideal above 2 %2 = [[2, [0, 1, 0]~, 3, 1, ...] 1] ? A = idealhnf(nf, 6*x, 4+2*x+x^2) %3 = [6 0 4] [0 6 2] [0 0 1] ? idealfactor(nf, A) %4 = [[2, [0, 1, 0]~, 3, 1, ...] 2] [[3, [1, 1, 0]~, 3, 1, ...] 2] ? idealfactor(nf, A, 3) \\ restrict to primes above p < 3 %5 = [[2, [0, 1, 0]~, 3, 1, ...] 2]
The library syntax is GEN gpidealfactor(GEN nf, GEN x, GEN lim = NULL)
.
This function should only be used by the gp
interface. Use
directly GEN idealfactor(GEN nf, GEN x)
or
GEN idealfactor_limit(GEN nf, GEN x, ulong lim)
.
Gives back the ideal corresponding to a factorization. The integer 1 corresponds to the empty factorization. If e is present, e and f must be vectors of the same length (e being integral), and the corresponding factorization is the product of the f[i]e[i].
If not, and f is vector, it is understood as in the preceding case with e
a vector of 1s: we return the product of the f[i]. Finally, f can be a
regular factorization, as produced by idealfactor
.
? nf = nfinit(y^2+1); idealfactor(nf, 4 + 2*y) %1 = [[2, [1, 1]~, 2, 1, [1, 1]~] 2] [[5, [2, 1]~, 1, 1, [-2, 1]~] 1] ? idealfactorback(nf, %) %2 = [10 4] [0 2] ? f = %1[,1]; e = %1[,2]; idealfactorback(nf, f, e) %3 = [10 4] [0 2] ? % == idealhnf(nf, 4 + 2*y) %4 = 1
If flag is nonzero, perform ideal reductions (idealred
) along the
way. This is most useful if the ideals involved are all extended
ideals (for instance with trivial principal part), so that the principal parts
extracted by idealred
are not lost. Here is an example:
? f = vector(#f, i, [f[i], [;]]); \\ transform to extended ideals ? idealfactorback(nf, f, e, 1) %6 = [[1, 0; 0, 1], [2, 1; [2, 1]~, 1]] ? nffactorback(nf, %[2]) %7 = [4, 2]~
The extended ideal returned in %6
is the trivial ideal 1, extended
with a principal generator given in factored form. We use nffactorback
to recover it in standard form.
The library syntax is GEN idealfactorback(GEN nf, GEN f, GEN e = NULL, long flag)
.
Let K be the number field defined by nf and assume K/ℚ be a
Galois extension with Galois group given gal = galoisinit(nf)
,
and that pr is an unramified prime ideal 𝔭 in prid
format.
This function returns a permutation of gal.group
which defines
the Frobenius element Frob𝔭 attached to 𝔭.
If p is the unique prime number in 𝔭, then
Frob(x) = xp mod 𝔭 for all x ∈ ℤK.
? nf = nfinit(polcyclo(31)); ? gal = galoisinit(nf); ? pr = idealprimedec(nf,101)[1]; ? g = idealfrobenius(nf,gal,pr); ? galoispermtopol(gal,g) %5 = x^8
This is correct since 101 = 8 mod 31.
The library syntax is GEN idealfrobenius(GEN nf, GEN gal, GEN pr)
.
Gives the Hermite normal form of the ideal uℤK+vℤK, where u and v are elements of the number field K defined by nf.
? nf = nfinit(y^3 - 2); ? idealhnf(nf, 2, y+1) %2 = [1 0 0] [0 1 0] [0 0 1] ? idealhnf(nf, y/2, [0,0,1/3]~) %3 = [1/3 0 0] [0 1/6 0] [0 0 1/6]
If v is omitted, returns the HNF of the ideal defined by u: u may be an
algebraic number (defining a principal ideal), a maximal ideal (as given by
idealprimedec
or idealfactor
), or a matrix whose columns give
generators for the ideal. This last format is a little complicated, but
useful to reduce general modules to the canonical form once in a while:
* if strictly less than N = [K:ℚ] generators are given, u is the ℤK-module they generate,
* if N or more are given, it is assumed that they form a
ℤ-basis of the ideal, in particular that the matrix has maximal rank N.
This acts as mathnf
since the ℤK-module structure is (taken for
granted hence) not taken into account in this case.
? idealhnf(nf, idealprimedec(nf,2)[1]) %4 = [2 0 0] [0 1 0] [0 0 1] ? idealhnf(nf, [1,2;2,3;3,4]) %5 = [1 0 0] [0 1 0] [0 0 1]
Finally, when K is quadratic with discriminant DK, we
allow u = Qfb(a,b,c)
, provided b2 - 4ac = DK. As usual,
this represents the ideal a ℤ + (1/2)(-b + sqrt{DK}) ℤ.
? K = nfinit(x^2 - 60); K.disc %1 = 60 ? idealhnf(K, qfbprimeform(60,2)) %2 = [2 1] [0 1] ? idealhnf(K, Qfb(1,2,3)) *** at top-level: idealhnf(K,Qfb(1,2,3 *** ^ — — — — — — -- *** idealhnf: Qfb(1, 2, 3) has discriminant != 60 in idealhnf.
The library syntax is GEN idealhnf0(GEN nf, GEN u, GEN v = NULL)
.
Also available is GEN idealhnf(GEN nf, GEN a)
, where nf
is a true nf structure.
Intersection of the two ideals A and B in the number field nf. The result is given in HNF.
? nf = nfinit(x^2+1); ? idealintersect(nf, 2, x+1) %2 = [2 0] [0 2]
This function does not apply to general ℤ-modules, e.g. orders, since its arguments are replaced by the ideals they generate. The following script intersects ℤ-modules A and B given by matrices of compatible dimensions with integer coefficients:
ZM_intersect(A,B) = { my(Ker = matkerint(concat(A,B))); mathnf( A * Ker[1..#A,] ) }
The library syntax is GEN idealintersect(GEN nf, GEN A, GEN B)
.
Inverse of the ideal x in the number field nf, given in HNF. If x is an extended ideal, its principal part is suitably updated: i.e. inverting [I,t], yields [I-1, 1/t].
The library syntax is GEN idealinv(GEN nf, GEN x)
.
Given nf a number field as output by nfinit
and an ideal
x, return 0 if x is not a maximal ideal. Otherwise return a prid
structure nf attached to the ideal. This function uses
ispseudoprime
and may return a wrong result in case the underlying
rational pseudoprime is not an actual prime number: apply isprime(pr.p)
to guarantee correctness. If x is an extended ideal, the extended part is
ignored.
? K = nfinit(y^2 + 1); ? idealismaximal(K, 3) \\ 3 is inert %2 = [3, [3, 0]~, 1, 2, 1] ? idealismaximal(K, 5) \\ 5 is not %3 = 0 ? pr = idealprimedec(K,5)[1] \\ already a prid %4 = [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] ? idealismaximal(K, pr) \\ trivial check %5 = [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]] ? x = idealhnf(K, pr) %6 = [5 3] [0 1] ? idealismaximal(K, x) \\ converts from matrix form to prid %7 = [5, [-2, 1]~, 1, 1, [2, -1; 1, 2]]
This function is noticeably faster than idealfactor
since it never involves an actually factorization, in particular when x
∩ ℤ is not a prime number.
The library syntax is GEN idealismaximal(GEN nf, GEN x)
.
Let nf be a number field and n > 0 be a positive integer. Return 1 if the fractional ideal A = Bn is an n-th power and 0 otherwise. If the argument B is present, set it to the n-th root of A, in HNF.
? K = nfinit(x^3 - 2); ? A = [46875, 30966, 9573; 0, 3, 0; 0, 0, 3]; ? idealispower(K, A, 3, &B) %3 = 1 ? B %4 = [75 22 41] [ 0 1 0] [ 0 0 1] ? A = [9375, 2841, 198; 0, 3, 0; 0, 0, 3]; ? idealispower(K, A, 3) %5 = 0
The library syntax is long idealispower(GEN nf, GEN A, long n, GEN *B = NULL)
.
Computes the list of all ideals of norm less or equal to bound in the number field nf. The result is a row vector with exactly bound components. Each component is itself a row vector containing the information about ideals of a given norm, in no specific order. The information is inferred from local data and Chinese remainders and less expensive than computing than a direct global computation.
The binary digits of flag mean:
* 1: if the ideals are given by a bid, include generators; otherwise don't.
* 2: if this bit is set, nf must be a bnf with units. Each
component is of the form [bid,U], where bid is attached to
an ideal f and U is a vector of discrete logarithms of the units in
(ℤK/f)*. More precisely, U gives the ideallog
s with respect
to bid of (ζ,u1,...,ur)
where ζ is the torsion unit generator bnf.tu[2]
and (ui)
are the fundamental units in bnf.fu
.
This structure is technical, meant to be used in conjunction with
bnrclassnolist
or bnrdisclist
.
* 4: give only the ideal (in HNF), else a bid.
* 8: omit ideals which cannot be conductors, i.e. divisible exactly my a prime ideal of norm 2.
? nf = nfinit(x^2+1); ? L = ideallist(nf, 100); ? L[1] %3 = [[1, 0; 0, 1]] \\ A single ideal of norm 1 ? #L[65] %4 = 4 \\ There are 4 ideals of norm 65 in ℤ[i]
If one wants more information:
? L = ideallist(nf, 100, 0); ? l = L[25]; vector(#l, i, l[i].clgp) %6 = [[20, [20]], [16, [4, 4]], [20, [20]]] ? l[1].mod %7 = [[25, 18; 0, 1], []] ? l[2].mod %8 = [[5, 0; 0, 5], []] ? l[3].mod %9 = [[25, 7; 0, 1], []]
where we ask for the structures of the (ℤ[i]/f)* for all
three ideals of norm 25. In fact, for all moduli with finite part of norm
25 and trivial Archimedean part, as the last 3 commands show. See
ideallistarch
to treat general moduli.
Finally, one can input a negative bound
. The function
then returns the ideals of norm |bound
|, given by their
factorization matrix. The only valid value of flag is then the default.
If needed, one can obtain their HNF using
idealfactorback
, and the corresponding bid structures using
idealstar
(which accepts ideals in factored form).
The library syntax is GEN gideallist(GEN nf, GEN bound, long flag)
.
Also available is
GEN ideallist0(GEN nf,long bound, long flag)
for a non-negative
bound.
list is a vector of vectors of bid's, as output by ideallist
with
flag 0 to 3. Return a vector of vectors with the same number of
components as the original list. The leaves give information about
moduli whose finite part is as in original list, in the same order, and
Archimedean part is now arch (it was originally trivial). The
information contained is of the same kind as was present in the input; see
ideallist
, in particular the meaning of flag.
? bnf = bnfinit(x^2-2); ? bnf.sign %2 = [2, 0] \\ two places at infinity ? L = ideallist(bnf, 100, 0); ? l = L[98]; vector(#l, i, l[i].clgp) %4 = [[42, [42]], [36, [6, 6]], [42, [42]]] ? La = ideallistarch(bnf, L, [1,1]); \\ add them to the modulus ? l = La[98]; vector(#l, i, l[i].clgp) %6 = [[168, [42, 2, 2]], [144, [6, 6, 2, 2]], [168, [42, 2, 2]]]
Of course, the results above are obvious: adding t places at infinity will add t copies of ℤ/2ℤ to (ℤK/f)*. The following application is more typical:
? L = ideallist(bnf, 100, 2); \\ units are required now ? La = ideallistarch(bnf, L, [1,1]); ? H = bnrclassnolist(bnf, La); ? H[98]; %4 = [2, 12, 2]
The library syntax is GEN ideallistarch(GEN nf, GEN list, GEN arch)
.
nf is a number field,
bid is as output by idealstar(nf, D,...)
and x an
element of nf which must have valuation
equal to 0 at all prime ideals in the support of D
and need not be
integral. This function
computes the discrete logarithm of x on the generators given in
bid.gen
. In other words, if gi are these generators, of orders
di respectively, the result is a column vector of integers (xi) such
that 0 ≤ xi < di and
x = ∏i gixi (mod *D) .
Note that when the support of D
contains places at infinity, this
congruence implies also sign conditions on the attached real embeddings.
See znlog
for the limitations of the underlying discrete log algorithms.
When nf is omitted, take it to be the rational number field. In that
case, x must be a t_INT
and bid must have been initialized by
znstar(N,1)
.
The library syntax is GEN ideallog(GEN nf = NULL, GEN x, GEN bid)
.
Also available are
GEN Zideallog(GEN bid, GEN x)
when nf
is NULL
,
and GEN ideallogmod(GEN nf, GEN x, GEN bid, GEN mod)
that returns the discrete logarithm of x modulo the t_INT
mod
; the value mod = NULL
is treated as 0 (full discrete
logarithm), but nf = NULL
is not implemented with nonzero mod
.
This function is useless and kept for backward compatibility only,
use idealred
. Computes a pseudo-minimum of the ideal x in the
direction vdir in the number field nf.
The library syntax is GEN idealmin(GEN nf, GEN ix, GEN vdir = NULL)
.
Ideal multiplication of the ideals x and y in the number field nf; the result is the ideal product in HNF. If either x or y are extended ideals, their principal part is suitably updated: i.e. multiplying [I,t], [J,u] yields [IJ, tu]; multiplying I and [J, u] yields [IJ, u].
? nf = nfinit(x^2 + 1); ? idealmul(nf, 2, x+1) %2 = [4 2] [0 2] ? idealmul(nf, [2, x], x+1) \\ extended ideal * ideal %3 = [[4, 2; 0, 2], x] ? idealmul(nf, [2, x], [x+1, x]) \\ two extended ideals %4 = [[4, 2; 0, 2], [-1, 0]~]
If flag is nonzero, reduce the result using idealred
.
The library syntax is GEN idealmul0(GEN nf, GEN x, GEN y, long flag)
.
See also
GEN idealmul(GEN nf, GEN x, GEN y)
(flag = 0) and
GEN idealmulred(GEN nf, GEN x, GEN y)
(flag ! = 0).
Computes the norm of the ideal x in the number field nf.
The library syntax is GEN idealnorm(GEN nf, GEN x)
.
Returns [A,B], where A,B are coprime integer ideals such that x = A/B, in the number field nf.
? nf = nfinit(x^2+1); ? idealnumden(nf, (x+1)/2) %2 = [[1, 0; 0, 1], [2, 1; 0, 1]]
The library syntax is GEN idealnumden(GEN nf, GEN x)
.
Computes the k-th power of the ideal x in the number field nf; k ∈ ℤ. If x is an extended ideal, its principal part is suitably updated: i.e. raising [I,t] to the k-th power, yields [Ik, tk].
If flag is nonzero, reduce the result using idealred
, throughout
the (binary) powering process; in particular, this is not the same
as idealpow
(nf,x,k) followed by reduction.
The library syntax is GEN idealpow0(GEN nf, GEN x, GEN k, long flag)
.
See also
GEN idealpow(GEN nf, GEN x, GEN k)
and
GEN idealpows(GEN nf, GEN x, long k)
(flag = 0).
Corresponding to flag = 1 is GEN idealpowred(GEN nf, GEN vp, GEN k)
.
Computes the prime ideal decomposition of the (positive) prime number p in the number field K represented by nf. If a nonprime p is given the result is undefined. If f is present and nonzero, restrict the result to primes of residue degree ≤ f.
The result is a vector of prid structures, each representing one of the
prime ideals above p in the number field nf. The representation
pr
= [p,a,e,f,mb] of a prime ideal means the following: a
is an algebraic integer in the maximal order ℤK and the prime ideal is
equal to 𝔭 = pℤK + aℤK;
e is the ramification index; f is the residual index;
finally, mb is the multiplication table attached to an algebraic
integer b such that 𝔭-1 = ℤK+ b/ pℤK, which is used
internally to compute valuations. In other words if p is inert,
then mb is the integer 1, and otherwise it is a square t_MAT
whose j-th column is b.nf.zk[j]
.
The algebraic number a is guaranteed to have a valuation equal to 1 at the prime ideal (this is automatic if e > 1).
The components of pr
should be accessed by member functions: pr.p
,
pr.e
, pr.f
, and pr.gen
(returns the vector [p,a]):
? K = nfinit(x^3-2); ? P = idealprimedec(K, 5); ? #P \\ 2 primes above 5 in Q(2^(1/3)) %3 = 2 ? [p1,p2] = P; ? [p1.e, p1.f] \\ the first is unramified of degree 1 %5 = [1, 1] ? [p2.e, p2.f] \\ the second is unramified of degree 2 %6 = [1, 2] ? p1.gen %7 = [5, [2, 1, 0]~] ? nfbasistoalg(K, %[2]) \\ a uniformizer for p1 %8 = Mod(x + 2, x^3 - 2) ? #idealprimedec(K, 5, 1) \\ restrict to f = 1 %9 = 1 \\ now only p1
The library syntax is GEN idealprimedec_limitf(GEN nf, GEN p, long f)
.
Given a prime ideal in idealprimedec
format,
returns the multiplicative group (1 + pr) / (1 + prk) as an
abelian group. This function is much faster than idealstar
when the
norm of pr is large, since it avoids (useless) work in the
multiplicative group of the residue field.
? K = nfinit(y^2+1); ? P = idealprimedec(K,2)[1]; ? G = idealprincipalunits(K, P, 20); ? G.cyc %4 = [512, 256, 4] \\ Z/512 x Z/256 x Z/4 ? G.gen %5 = [[-1, -2]~, 1021, [0, -1]~] \\ minimal generators of given order
The library syntax is GEN idealprincipalunits(GEN nf, GEN pr, long k)
.
Let K be the number field defined by nf and assume that K/ℚ is
Galois with Galois group G given by gal = galoisinit(nf)
.
Let pr be the prime ideal 𝔓 in prid format.
This function returns a vector g of subgroups of gal
as follows:
* g[1]
is the decomposition group of 𝔓,
* g[2]
is G0(𝔓), the inertia group of 𝔓,
and for i ≥ 2,
* g[i]
is Gi-2(𝔓), the i-2-th
ramification group of 𝔓.
The length of g is the number of nontrivial groups in the sequence, thus is 0 if e = 1 and f = 1, and 1 if f > 1 and e = 1. The following function computes the cardinality of a subgroup of G, as given by the components of g:
card(H) =my(o=H[2]); prod(i=1,#o,o[i]);
? nf=nfinit(x^6+3); gal=galoisinit(nf); pr=idealprimedec(nf,3)[1]; ? g = idealramgroups(nf, gal, pr); ? apply(card,g) %3 = [6, 6, 3, 3, 3] \\ cardinalities of the Gi
? nf=nfinit(x^6+108); gal=galoisinit(nf); pr=idealprimedec(nf,2)[1]; ? iso=idealramgroups(nf,gal,pr)[2] %5 = [[Vecsmall([2, 3, 1, 5, 6, 4])], Vecsmall([3])] ? nfdisc(galoisfixedfield(gal,iso,1)) %6 = -3
The field fixed by the inertia group of 2 is not ramified at 2.
The library syntax is GEN idealramgroups(GEN nf, GEN gal, GEN pr)
.
LLL reduction of
the ideal I in the number field K attached to nf, along the
direction v. The v parameter is best left omitted, but if it is present,
it must be an nf.r1
+ nf.r2
-component vector of
nonnegative integers. (What counts is the relative magnitude of the
entries: if all entries are equal, the effect is the same as if the vector
had been omitted.)
This function finds an a ∈ K* such that J = (a)I is "small" and integral (see the end for technical details). The result is the Hermite normal form of the "reduced" ideal J.
? K = nfinit(y^2+1); ? P = idealprimedec(K,5)[1]; ? idealred(K, P) %3 = [1 0] [0 1]
More often than not, a principal ideal yields the unit
ideal as above. This is a quick and dirty way to check if ideals are principal,
but it is not a necessary condition: a nontrivial result does not prove that
the ideal is nonprincipal. For guaranteed results, see bnfisprincipal
,
which requires the computation of a full bnf
structure.
If the input is an extended ideal [I,s], the output is [J, sa]; in this way, one keeps track of the principal ideal part:
? idealred(K, [P, 1]) %5 = [[1, 0; 0, 1], [2, -1]~]
meaning that P is generated by [2, -1] . The number field element in the
extended part is an algebraic number in any form or a factorization
matrix (in terms of number field elements, not ideals!). In the latter case,
elements stay in factored form, which is a convenient way to avoid
coefficient explosion; see also idealpow
.
Technical note. The routine computes an LLL-reduced
basis for the lattice I-1 equipped with the quadratic
form
|| x ||v2 = ∑i = 1r1+r2
2viϵi|σi(x)|2,
where as usual the σi are the (real and) complex embeddings and
ϵi = 1, resp. 2, for a real, resp. complex place. The element
a is simply the first vector in the LLL basis. The only reason you may want
to try to change some directions and set some vi ! = 0 is to randomize
the elements found for a fixed ideal, which is heuristically useful in index
calculus algorithms like bnfinit
and bnfisprincipal
.
Even more technical note. In fact, the above is a white lie. We do not use ||.||v exactly but a rescaled rounded variant which gets us faster and simpler LLLs. There's no harm since we are not using any theoretical property of a after all, except that it belongs to I-1 and that a I is "expected to be small".
The library syntax is GEN idealred0(GEN nf, GEN I, GEN v = NULL)
.
Let nf be a number field, x an ideal in nf and n > 0 be a positive integer. Return a number field element b such that x bn = v is small. If x is integral, then v is also integral.
More precisely, idealnumden
reduces the problem to x integral. Then,
factoring out the prime ideals dividing a rational prime p ≤ B,
we rewrite x = I Jn where the ideals I and J are both integral and
I is B-smooth. Then we return a small element b in J-1.
The bound B avoids a costly complete factorization of x; as soon as the n-core of x is B-smooth (i.e., as soon as I is n-power free), then J is as large as possible and so is the expected reduction.
? T = x^6+108; nf = nfinit(T); a = Mod(x,T); ? setrand(1); u = (2*a^2+a+3)*random(2^1000*x^6)^6; ? sizebyte(u) %3 = 4864 ? b = idealredmodpower(nf,u,2); ? v2 = nfeltmul(nf,u, nfeltpow(nf,b,2)) %5 = [34, 47, 15, 35, 9, 3]~ ? b = idealredmodpower(nf,u,6); ? v6 = nfeltmul(nf,u, nfeltpow(nf,b,6)) %7 = [3, 0, 2, 6, -7, 1]~
The last element v6
, obtained by reducing
modulo 6-th powers instead of squares, looks smaller than v2
but its norm is actually a little larger:
? idealnorm(nf,v2) %8 = 81309 ? idealnorm(nf,v6) %9 = 731781
The library syntax is GEN idealredmodpower(GEN nf, GEN x, ulong n, ulong B)
.
Outputs a bid
structure,
necessary for computing in the finite abelian group G = (ℤK/N)*. Here,
nf is a number field and N is a modulus: either an ideal in any
form, or a row vector whose first component is an ideal and whose second
component is a row vector of r1 0 or 1. Ideals can also be given
by a factorization into prime ideals, as produced by idealfactor
.
If the positive integer cycmod
is present, only compute the group
modulo cycmod
-th powers, which may save a lot of time when some
maximal ideals in the modulus have a huge residue field. Whereas you might
only be interested in quadratic or cubic residuosity; see also bnrinit
for applications in class field theory.
This bid is used in ideallog
to compute discrete logarithms. It
also contains useful information which can be conveniently retrieved as
bid.mod
(the modulus),
bid.clgp
(G as a finite abelian group),
bid.no
(the cardinality of G),
bid.cyc
(elementary divisors) and
bid.gen
(generators).
If flag = 1 (default), the result is a bid
structure without
generators: they are well defined but not explicitly computed, which saves
time.
If flag = 2, as flag = 1, but including generators.
If flag = 0, only outputs (ℤK/N)* as an abelian group, i.e as a 3-component vector [h,d,g]: h is the order, d is the vector of SNF cyclic components and g the corresponding generators.
If nf is omitted, we take it to be the rational number fields, N must
be an integer and we return the structure of (ℤ/Nℤ)*. In other words
idealstar(, N, flag)
is short for
idealstar(nfinit(x), N, flag)
but faster. The alternative syntax znstar(N, flag)
is also available for an analogous effect but, due to an unfortunate
historical oversight, the default value of flag is different in
the two functions (znstar
does not initialize by default, you probably
want znstar(N,1)
).
The library syntax is GEN idealstarmod(GEN nf = NULL, GEN N, long flag, GEN cycmod = NULL)
.
Instead the above hardcoded numerical flags, one should rather use
GEN Idealstarmod(GEN nf, GEN ideal, long flag, GEN cycmod)
or
GEN Idealstar(GEN nf, GEN ideal, long flag)
(cycmod
is
NULL
), where flag is
an or-ed combination of nf_GEN
(include generators) and nf_INIT
(return a full bid
, not a group), possibly 0. This offers
one more combination: gen, but no init. The nf
argument must be a true
nf structure.
Computes a two-element representation of the ideal x in the number field nf, combining a random search and an approximation theorem; x is an ideal in any form (possibly an extended ideal, whose principal part is ignored)
* When called as idealtwoelt(nf,x)
, the result is a row vector
[a,α] with two components such that x = aℤK+αℤK and a is
chosen to be the positive generator of x∩ℤ, unless x was given as a
principal ideal in which case we may choose a = 0. The algorithm
uses a fast lazy factorization of x∩ ℤ and runs in randomized
polynomial time.
? K = nfinit(t^5-23); ? x = idealhnf(K, t^2*(t+1), t^3*(t+1)) %2 = \\ some random ideal of norm 552*23 [552 23 23 529 23] [ 0 23 0 0 0] [ 0 0 1 0 0] [ 0 0 0 1 0] [ 0 0 0 0 1] ? [a,alpha] = idealtwoelt(K, x) %3 = [552, [23, 0, 1, 0, 0]~] ? nfbasistoalg(K, alpha) %4 = Mod(t^2 + 23, t^5 - 23)
* When called as idealtwoelt(nf,x,a)
with an explicit nonzero a
supplied as third argument, the function assumes that a ∈ x and returns
α ∈ x such that x = aℤK + αℤK. Note that we must factor
a in this case, and the algorithm is generally slower than the
default variant and gives larger generators:
? alpha2 = idealtwoelt(K, x, 552) %5 = [-161, -161, -183, -207, 0]~ ? idealhnf(K, 552, alpha2) == x %6 = 1
Note that, in both cases, the return value is not
recognized as an ideal by GP functions; one must use idealhnf
as
above to recover a valid ideal structure from the two-element representation.
The library syntax is GEN idealtwoelt0(GEN nf, GEN x, GEN a = NULL)
.
Also available are
GEN idealtwoelt(GEN nf, GEN x)
and
GEN idealtwoelt2(GEN nf, GEN x, GEN a)
.
Gives the valuation of the ideal x at the prime ideal pr in the
number field nf, where pr is in idealprimedec
format.
The valuation of the 0 ideal is +oo
.
The library syntax is GEN gpidealval(GEN nf, GEN x, GEN pr)
.
Also available is
long idealval(GEN nf, GEN x, GEN pr)
, which returns
LONG_MAX
if x = 0 and the valuation as a long
integer.
This function is deprecated, use apply
.
nf being a number field in nfinit
format, and x a
(row or column) vector or matrix, apply nfalgtobasis
to each entry
of x.
The library syntax is GEN matalgtobasis(GEN nf, GEN x)
.
This function is deprecated, use apply
.
nf being a number field in nfinit
format, and x a
(row or column) vector or matrix, apply nfbasistoalg
to each entry
of x.
The library syntax is GEN matbasistoalg(GEN nf, GEN x)
.
Let z = Mod(A, T)
be a polmod, and Q be its minimal
polynomial, which must satisfy deg(Q) = deg(T).
Returns a "reverse polmod" Mod(B, Q)
, which is a root of T.
This is quite useful when one changes the generating element in algebraic extensions:
? u = Mod(x, x^3 - x -1); v = u^5; ? w = modreverse(v) %2 = Mod(x^2 - 4*x + 1, x^3 - 5*x^2 + 4*x - 1)
which means that x3 - 5x2 + 4x -1 is another defining polynomial for the cubic field ℚ(u) = ℚ[x]/(x3 - x - 1) = ℚ[x]/(x3 - 5x2 + 4x - 1) = ℚ(v), and that u → v2 - 4v + 1 gives an explicit isomorphism. From this, it is easy to convert elements between the A(u) ∈ ℚ(u) and B(v) ∈ ℚ(v) representations:
? A = u^2 + 2*u + 3; subst(lift(A), 'x, w) %3 = Mod(x^2 - 3*x + 3, x^3 - 5*x^2 + 4*x - 1) ? B = v^2 + v + 1; subst(lift(B), 'x, v) %4 = Mod(26*x^2 + 31*x + 26, x^3 - x - 1)
If the minimal polynomial of z has lower degree than expected, the routine fails
? u = Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1) ? modreverse(u) *** modreverse: domain error in modreverse: deg(minpoly(z)) < 4 *** Break loop: type 'break' to go back to GP prompt break> Vec( dbg_err() ) \\ ask for more info ["e_DOMAIN", "modreverse", "deg(minpoly(z))", "<", 4, Mod(-x^3 + 9*x, x^4 - 10*x^2 + 1)] break> minpoly(u) x^2 - 8
The library syntax is GEN modreverse(GEN z)
.
Gives the vector of the slopes of the Newton
polygon of the polynomial x with respect to the prime number p. The n
components of the vector are in decreasing order, where n is equal to the
degree of x. Vertical slopes occur iff the constant coefficient of x is
zero and are denoted by +oo
.
The library syntax is GEN newtonpoly(GEN x, GEN p)
.
Given an algebraic number x in the number field nf,
transforms it to a column vector on the integral basis nf.zk
.
? nf = nfinit(y^2 + 4); ? nf.zk %2 = [1, 1/2*y] ? nfalgtobasis(nf, [1,1]~) %3 = [1, 1]~ ? nfalgtobasis(nf, y) %4 = [0, 2]~ ? nfalgtobasis(nf, Mod(y, y^2+4)) %5 = [0, 2]~
This is the inverse function of nfbasistoalg
.
The library syntax is GEN algtobasis(GEN nf, GEN x)
.
Let T(X) be an irreducible polynomial with integral coefficients. This
function returns an integral basis of the number field defined by T,
that is a ℤ-basis of its maximal order. If present, dK
is set
to the discriminant of the returned order. The basis elements are given as
elements in K = ℚ[X]/(T), in Hermite normal form with respect to the
ℚ-basis (1,X,...,Xdeg T-1) of K, lifted to ℚ[X].
In particular its first element is always 1 and its i-th element is a
polynomial of degree i-1 whose leading coefficient is the inverse of an
integer: the product of those integers is the index of ℤ[X]/(T) in the
maximal order ℤK:
? nfbasis(x^2 + 4) \\ Z[X]/(T) has index 2 in ZK %1 = [1, x/2] ? nfbasis(x^2 + 4, &D) %2 = [1, x/2] ? D %3 = -4
This function uses a modified version of the round 4 algorithm, due to David Ford, Sebastian Pauli and Xavier Roblot.
Local basis, orders maximal at certain primes.
Obtaining the maximal order is hard: it requires factoring the discriminant D of T. Obtaining an order which is maximal at a finite explicit set of primes is easy, but it may then be a strict suborder of the maximal order. To specify that we are interested in a given set of places only, we can replace the argument T by an argument [T,listP], where listP encodes the primes we are interested in: it must be a factorization matrix, a vector of integers or a single integer.
* Vector: we assume that it contains distinct prime numbers.
* Matrix: we assume that it is a two-column matrix of a (partial) factorization of D; namely the first column contains distinct primes and the second one the valuation of D at each of these primes.
* Integer B: this is replaced by the vector of primes up to B. Note that the function will use at least O(B) time: a small value, about 105, should be enough for most applications. Values larger than 232 are not supported.
In all these cases, the primes may or may not divide the discriminant D
of T. The function then returns a ℤ-basis of an order whose index is
not divisible by any of these prime numbers. The result may actually be
a global integral basis, in particular if all the prime divisors of the
field discriminant are included, but this is not guaranteed!
Note that nfinit
has built-in support for such a check:
? K = nfinit([T, listP]); ? nfcertify(K) \\ we computed an actual maximal order %2 = [];
The first line initializes a number field structure
incorporating nfbasis([T, listP]
in place of a proven integral basis.
The second line certifies that the resulting structure is correct. This
allows to create an nf
structure attached to the number field K =
ℚ[X]/(T), when the discriminant of T cannot be factored completely,
whereas the prime divisors of disc K are known. If present, the argument
dK
is set to the discriminant of the returned order, and is
equal to the field discriminant if and only if the order is maximal.
Of course, if listP contains a single prime number p, the function returns a local integral basis for ℤp[X]/(T):
? nfbasis(x^2+x-1001) %1 = [1, 1/3*x - 1/3] ? nfbasis( [x^2+x-1001, [2]] ) %2 = [1, x]
The following function computes the index iT of ℤ[X]/(T) in the order generated by the ℤ-basis B:
nfbasisindex(T, B) = vecprod([denominator(pollead(Q)) | Q <- B]);
In particular, B is a basis of the maximal order
if and only if poldisc
(T) / iT2 is equal to the field
discriminant. More generally, this formula gives the square of index of the
order given by B in ℤK. For instance, assume that P is a vector
of prime numbers containing (at least) all prime divisors of the field
discriminant, then the following construct allows to provably compute the
field discriminant and to check whether the returned basis is actually
a basis of the maximal order
? B = nfbasis([T, P], &D); ? dK = sign(D) * vecprod([p^valuation(D,p) | p<-P]); ? dK * nfbasisindex(T, B)^2 == poldisc(T)
The variable dK
contains the field discriminant and
the last command returns 1 if and only if B is a ℤ-basis of the
maximal order. Of course, the nfinit
/ nfcertify
approach is
simpler, but it is also more costly.
The Buchmann-Lenstra algorithm.
We now complicate the picture: it is in fact allowed to include
composite numbers instead of primes
in listP
(Vector or Matrix case), provided they are pairwise coprime.
The result may still be a correct integral basis if
the field discriminant factors completely over the actual primes in the
list; again, this is not guaranteed. Adding a composite C such that C2
divides D may help because when we consider C as a prime and run
the algorithm, two good things can happen: either we succeed in proving that
no prime dividing C can divide the index (without actually needing to find
those primes), or the computation exhibits a nontrivial zero divisor,
thereby factoring C and we go on with the refined factorization. (Note that
including a C such that C2 does not divide D is useless.) If neither
happen, then the computed basis need not generate the maximal order. Here is
an example:
? B = 10^5; ? listP = factor(poldisc(T), B); \\ primes <= B dividing D + cofactor ? basis = nfbasis([T, listP], &D)
If the computed discriminant D factors completely
over the primes less than B (together with the primes contained in the
addprimes
table), then everything is certified: D is the field
discriminant and basis
generates the maximal order.
This can be tested as follows:
F = factor(D, B); P = F[,1]; E = F[,2]; for (i = 1, #P, if (P[i] > B && !isprime(P[i]), warning("nf may be incorrect")));
This is a sufficient but not a necessary condition, hence the warning, instead of an error.
The function nfcertify
speeds up and automates the above process:
? B = 10^5; ? nf = nfinit([T, B]); ? nfcertify(nf) %3 = [] \\ nf is unconditionally correct ? [basis, disc] = [nf.zk, nf.disc];
The library syntax is GEN nfbasis(GEN T, GEN *dK = NULL)
.
Given an algebraic number x in the number field nf, transforms it
into t_POLMOD
form.
? nf = nfinit(y^2 + 4); ? nf.zk %2 = [1, 1/2*y] ? nfbasistoalg(nf, [1,1]~) %3 = Mod(1/2*y + 1, y^2 + 4) ? nfbasistoalg(nf, y) %4 = Mod(y, y^2 + 4) ? nfbasistoalg(nf, Mod(y, y^2+4)) %5 = Mod(y, y^2 + 4)
This is the inverse function of nfalgtobasis
.
The library syntax is GEN basistoalg(GEN nf, GEN x)
.
nf being as output by
nfinit
, checks whether the integer basis is known unconditionally.
This is in particular useful when the argument to nfinit
was of the
form [T, listP
], specifying a finite list of primes when
p-maximality had to be proven, or a list of coprime integers to which
Buchmann-Lenstra algorithm was to be applied.
The function returns a vector of coprime composite integers. If this vector
is empty, then nf.zk
and nf.disc
are correct. Otherwise, the
result is dubious. In order to obtain a certified result, one must completely
factor each of the given integers, then addprime
each of their prime
factors, then check whether nfdisc(nf.pol)
is equal to nf.disc
.
The library syntax is GEN nfcertify(GEN nf)
.
Let nf be a number field structure attached to the field K and let P and Q be squarefree polynomials in K[X] in the same variable. Outputs the simple factors of the étale K-algebra A = K[X, Y] / (P(X), Q(Y)). The factors are given by a list of polynomials R in K[X], attached to the number field K[X]/ (R), and sorted by increasing degree (with respect to lexicographic ordering for factors of equal degrees). Returns an error if one of the polynomials is not squarefree.
Note that it is more efficient to reduce to the case where P and Q are irreducible first. The routine will not perform this for you, since it may be expensive, and the inputs are irreducible in most applications anyway. In this case, there will be a single factor R if and only if the number fields defined by P and Q are linearly disjoint (their intersection is K).
The binary digits of flag mean
1: outputs a vector of 4-component vectors [R,a,b,k], where R ranges through the list of all possible compositums as above, and a (resp. b) expresses the root of P (resp. Q) as an element of K[X]/(R). Finally, k is a small integer such that b + ka = X modulo R.
2: assume that P and Q define number fields that are linearly disjoint: both polynomials are irreducible and the corresponding number fields have no common subfield besides K. This allows to save a costly factorization over K. In this case return the single simple factor instead of a vector with one element.
A compositum is often defined by a complicated polynomial, which it is advisable to reduce before further work. Here is an example involving the field K(ζ5, 51/10), K = ℚ(sqrt{5}):
? K = nfinit(y^2-5);
? L = nfcompositum(K, x^5 - y, polcyclo(5), 1); \\ list of [R,a,b,k]
? [R, a] = L[1]; \\ pick the single factor, extract R,a (ignore b,k)
? lift(R) \\ defines the compositum
%4 = x^10 + (-5/2*y + 5/2)*x^9 + (-5*y + 20)*x^8 + (-20*y + 30)*x^7 + \
(-45/2*y + 145/2)*x^6 + (-71/2*y + 121/2)*x^5 + (-20*y + 60)*x^4 + \
(-25*y + 5)*x^3 + 45*x^2 + (-5*y + 15)*x + (-2*y + 6)
? a^5 - y \\ a fifth root of y
%5 = 0
? [T, X] = rnfpolredbest(K, R, 1);
? lift(T) \\ simpler defining polynomial for K[x]/(R)
%7 = x^10 + (-11/2*y + 25/2)
? liftall(X) \\ root of R in K[x]/(T(x))
%8 = (3/4*y + 7/4)*x^7 + (-1/2*y - 1)*x^5 + 1/2*x^2 + (1/4*y - 1/4)
? a = subst(a.pol, 'x, X); \\ a
in the new coordinates
? liftall(a)
%10 = (-3/4*y - 7/4)*x^7 - 1/2*x^2
? a^5 - y
%11 = 0
The main variables of P and Q must be the same and have higher priority
than that of nf (see varhigher
and varlower
).
The library syntax is GEN nfcompositum(GEN nf, GEN P, GEN Q, long flag)
.
Given a pseudo-matrix x, computes a
nonzero ideal contained in (i.e. multiple of) the determinant of x. This
is particularly useful in conjunction with nfhnfmod
.
The library syntax is GEN nfdetint(GEN nf, GEN x)
.
field discriminant of the number field defined by the integral, preferably monic, irreducible polynomial T(X). Returns the discriminant of the number field ℚ[X]/(T), using the Round 4 algorithm.
Local discriminants, valuations at certain primes.
As in nfbasis
, the argument T can be replaced by [T,listP],
where listP
is as in nfbasis
: a vector of pairwise coprime
integers (usually distinct primes), a factorization matrix, or a single
integer. In that case, the function returns the discriminant of an order
whose basis is given by nfbasis(T,listP)
, which need not be the maximal
order, and whose valuation at a prime entry in listP
is the same as the
valuation of the field discriminant.
In particular, if listP
is [p] for a prime p, we can
return the p-adic discriminant of the maximal order of ℤp[X]/(T),
as a power of p, as follows:
? padicdisc(T,p) = p^valuation(nfdisc([T,[p]]), p); ? nfdisc(x^2 + 6) %2 = -24 ? padicdisc(x^2 + 6, 2) %3 = 8 ? padicdisc(x^2 + 6, 3) %4 = 3
The following function computes the discriminant of the maximal order under the assumption that P is a vector of prime numbers containing (at least) all prime divisors of the field discriminant:
globaldisc(T, P) = { my (D = nfdisc([T, P])); sign(D) * vecprod([p^valuation(D,p) | p <-P]); } ? globaldisc(x^2 + 6, [2, 3, 5]) %1 = -24
The library syntax is nfdisc(GEN T)
. Also available is GEN nfbasis(GEN T, GEN *d)
,
which returns the order basis, and where *d
receives the order
discriminant.
Given a polynomial T with integer coefficients, return
[D, faD] where D is nfdisc
(T) and
faD is the factorization of |D|. All the variants [T,listP]
are allowed (see ??nfdisc
), in which case faD is the
factorization of the discriminant underlying order (which need not be maximal
at the primes not specified by listP
) and the factorization may
contain large composites.
? T = x^3 - 6021021*x^2 + 12072210077769*x - 8092423140177664432; ? [D,faD] = nfdiscfactors(T); print(faD); D [3, 3; 500009, 2] %2 = -6750243002187] ? T = x^3 + 9*x^2 + 27*x - 125014250689643346789780229390526092263790263725; ? [D,faD] = nfdiscfactors(T); print(faD); D [3, 3; 1000003, 2] %4 = -27000162000243 ? [D,faD] = nfdiscfactors([T, 10^3]); print(faD) [3, 3; 125007125141751093502187, 2]
In the final example, we only get a partial factorization, which is only guaranteed correct at primes ≤ 103.
The function also accept number field structures, for instance as output by
nfinit
, and returns the field discriminant and its factorization:
? T = x^3 + 9*x^2 + 27*x - 125014250689643346789780229390526092263790263725; ? nf = nfinit(T); [D,faD] = nfdiscfactors(T); print(faD); D %2 = -27000162000243 ? nf.disc %3 = -27000162000243
The library syntax is GEN nfdiscfactors(GEN T)
.
Given two elements x and y in nf, computes their sum x+y in the number field nf.
? nf = nfinit(1+x^2); ? nfeltadd(nf, 1, x) \\ 1 + I %2 = [1, 1]~
The library syntax is GEN nfadd(GEN nf, GEN x, GEN y)
.
Given two elements x and y in nf, computes their quotient x/y in the number field nf.
The library syntax is GEN nfdiv(GEN nf, GEN x, GEN y)
.
Given two elements x and y in
nf, computes an algebraic integer q in the number field nf
such that the components of x-qy are reasonably small. In fact, this is
functionally identical to round(nfdiv(nf,x,y))
.
The library syntax is GEN nfdiveuc(GEN nf, GEN x, GEN y)
.
This function is obsolete, use nfmodpr
.
Given two elements x
and y in nf and pr a prime ideal in modpr
format (see
nfmodprinit
), computes their quotient x / y modulo the prime ideal
pr.
The library syntax is GEN nfdivmodpr(GEN nf, GEN x, GEN y, GEN pr)
.
This function is normally useless in library mode. Project your
inputs to the residue field using nf_to_Fq
, then work there.
Given two elements x and y in nf, gives a two-element row vector [q,r] such that x = qy+r, q is an algebraic integer in nf, and the components of r are reasonably small.
The library syntax is GEN nfdivrem(GEN nf, GEN x, GEN y)
.
Given an element x in the number field nf, return
the (real or) complex embeddings of x specified by optional argument
pl, at the current realprecision
:
* pl omitted: return the vector of embeddings at all r1+r2 places;
* pl an integer between 1 and r1+r2: return the
i-th embedding of x, attached to the i-th root of nf.pol
,
i.e. nf.roots[i]
;
* pl a vector or t_VECSMALL
: return the vector of embeddings; the i-th
entry gives the embedding at the place attached to the pl[i]-th real
root of nf.pol
.
? nf = nfinit('y^3 - 2); ? nf.sign %2 = [1, 1] ? nfeltembed(nf, 'y) %3 = [1.25992[...], -0.62996[...] + 1.09112[...]*I]] ? nfeltembed(nf, 'y, 1) %4 = 1.25992[...] ? nfeltembed(nf, 'y, 3) \\ there are only 2 arch. places *** at top-level: nfeltembed(nf,'y,3) *** ^ — — — — — -- *** nfeltembed: domain error in nfeltembed: index > 2
The library syntax is GEN nfeltembed(GEN nf, GEN x, GEN pl = NULL, long prec)
.
Returns 1 if x is an n-th power in the number field nf
(and sets y to an n-th root if the
argument is present), else returns 0.
? nf = nfinit(1+x^2); ? nfeltispower(nf, -4, 4, &y) %2 = 1 ? y %3 = [-1, -1]~
The library syntax is long nfispower(GEN nf, GEN x, long n, GEN *y = NULL)
.
Returns 1 if x is a square in nf
(and sets y to a square root if the
argument is present), else returns 0.
? nf = nfinit(1+x^2); ? nfeltissquare(nf, -1, &y) %2 = 1 ? y %3 = [0, -1]~
The library syntax is long nfissquare(GEN nf, GEN x, GEN *y = NULL)
.
Given two elements x and y in
nf, computes an element r of nf of the form r = x-qy with
q and algebraic integer, and such that r is small. This is functionally
identical to
x - nfmul(nf,round(nfdiv(nf,x,y)),y)
.
The library syntax is GEN nfmod(GEN nf, GEN x, GEN y)
.
Given two elements x and y in nf, computes their product x*y in the number field nf.
The library syntax is GEN nfmul(GEN nf, GEN x, GEN y)
.
This function is obsolete, use nfmodpr
.
Given two elements x and
y in nf and pr a prime ideal in modpr
format (see
nfmodprinit
), computes their product x*y modulo the prime ideal
pr.
The library syntax is GEN nfmulmodpr(GEN nf, GEN x, GEN y, GEN pr)
.
This function is normally useless in library mode. Project your
inputs to the residue field using nf_to_Fq
, then work there.
Returns the absolute norm of x.
The library syntax is GEN nfnorm(GEN nf, GEN x)
.
Given an element x in nf, and a positive or negative integer k, computes xk in the number field nf.
The library syntax is GEN nfpow(GEN nf, GEN x, GEN k)
.
GEN nfinv(GEN nf, GEN x)
correspond to k = -1, and
GEN nfsqr(GEN nf,GEN x)
to k = 2.
This function is obsolete, use nfmodpr
.
Given an element x in nf, an integer k and a prime ideal
pr in modpr
format
(see nfmodprinit
), computes xk modulo the prime ideal pr.
The library syntax is GEN nfpowmodpr(GEN nf, GEN x, GEN k, GEN pr)
.
This function is normally useless in library mode. Project your
inputs to the residue field using nf_to_Fq
, then work there.
Given an ideal id in Hermite normal form and an element a of the number field nf, finds an element r in nf such that a-r belongs to the ideal and r is small.
The library syntax is GEN nfreduce(GEN nf, GEN a, GEN id)
.
This function is obsolete, use nfmodpr
.
Given an element x of the number field nf and a prime ideal
pr in modpr
format compute a canonical representative for the
class of x modulo pr.
The library syntax is GEN nfreducemodpr(GEN nf, GEN x, GEN pr)
.
This function is normally useless in library mode. Project your
inputs to the residue field using nf_to_Fq
, then work there.
Given an element x in the number field nf, returns the signs of the real embeddings of x specified by optional argument pl:
* pl omitted: return the vector of signs at all r1 real places;
* pl an integer between 1 and r1: return the sign of the
i-th embedding of x, attached to the i-th real root of nf.pol
,
i.e. nf.roots[i]
;
* pl a vector or t_VECSMALL
: return the vector of signs; the i-th
entry gives the sign at the real place attached to the pl[i]-th real
root of nf.pol
.
? nf = nfinit(polsubcyclo(11,5,'y)); \\ Q(cos(2 pi/11)) ? nf.sign %2 = [5, 0] ? x = Mod('y, nf.pol); ? nfeltsign(nf, x) %4 = [-1, -1, -1, 1, 1] ? nfeltsign(nf, x, 1) %5 = -1 ? nfeltsign(nf, x, [1..4]) %6 = [-1, -1, -1, 1] ? nfeltsign(nf, x, 6) \\ there are only 5 real embeddings *** at top-level: nfeltsign(nf,x,6) *** ^ — — — — — -- *** nfeltsign: domain error in nfeltsign: index > 5
The library syntax is GEN nfeltsign(GEN nf, GEN x, GEN pl = NULL)
.
Returns the absolute trace of x.
The library syntax is GEN nftrace(GEN nf, GEN x)
.
Given an element x in
nf and a prime ideal pr in the format output by
idealprimedec
, computes the valuation v at pr of the
element x. The valuation of 0 is +oo
.
? nf = nfinit(x^2 + 1); ? P = idealprimedec(nf, 2)[1]; ? nfeltval(nf, x+1, P) %3 = 1
This particular valuation can also be obtained using
idealval(nf,x,pr)
, since x is then converted to a
principal ideal.
If the y argument is present, sets y = x τv, where τ is a
fixed "anti-uniformizer" for pr: its valuation at pr is -1;
its valuation is 0 at other prime ideals dividing pr.p
and
nonnegative at all other primes. In other words y is the part of x
coprime to pr. If x is an algebraic integer, so is y.
? nfeltval(nf, x+1, P, &y); y %4 = [0, 1]~
For instance if x = ∏i xiei is known to be coprime to
pr, where the xi are algebraic integers and ei ∈ ℤ then,
if vi = nfeltval
(nf, xi, pr, &yi), we still
have x = ∏i yiei, where the yi are still algebraic
integers but now all of them are coprime to pr. They can then be
mapped to the residue field of pr more efficiently than if the product
had been expanded beforehand: we can reduce mod pr after each ring
operation.
The library syntax is GEN gpnfvalrem(GEN nf, GEN x, GEN pr, GEN *y = NULL)
.
Also available are
long nfvalrem(GEN nf, GEN x, GEN pr, GEN *y = NULL)
, which returns
LONG_MAX
if x = 0 and the valuation as a long
integer,
and long nfval(GEN nf, GEN x, GEN pr)
, which only returns the
valuation (y = NULL
).
Factorization of the univariate
polynomial (or rational function) T over the number field nf given
by nfinit
; T has coefficients in nf (i.e. either scalar,
polmod, polynomial or column vector). The factors are sorted by increasing
degree.
The main variable of nf must be of lower
priority than that of T, see Section se:priority. However if
the polynomial defining the number field occurs explicitly in the
coefficients of T as modulus of a t_POLMOD
or as a t_POL
coefficient, its main variable must be the same as the main variable
of T. For example,
? nf = nfinit(y^2 + 1); ? nffactor(nf, x^2 + y); \\ OK ? nffactor(nf, x^2 + Mod(y, y^2+1)); \\ OK ? nffactor(nf, x^2 + Mod(z, z^2+1)); \\ WRONG
It is possible to input a defining polynomial for nf
instead, but this is in general less efficient since parts of an nf
structure will then be computed internally. This is useful in two
situations: when you do not need the nf
elsewhere, or when you cannot
initialize an nf
due to integer factorization difficulties when
attempting to compute the field discriminant and maximal order. In all
cases, the function runs in polynomial time using Belabas's variant
of van Hoeij's algorithm, which copes with hundreds of modular factors.
Caveat. nfinit([T, listP])
allows to compute in polynomial
time a conditional nf structure, which sets nf.zk
to an order
which is not guaranteed to be maximal at all primes. Always either use
nfcertify
first (which may not run in polynomial time) or make sure
to input nf.pol
instead of the conditional nf: nffactor
is
able to recover in polynomial time in this case, instead of potentially
missing a factor.
The library syntax is GEN nffactor(GEN nf, GEN T)
.
Gives back the nf element corresponding to a factorization. The integer 1 corresponds to the empty factorization.
If e is present, e and f must be vectors of the same length (e being integral), and the corresponding factorization is the product of the f[i]e[i].
If not, and f is vector, it is understood as in the preceding case with e a vector of 1s: we return the product of the f[i]. Finally, f can be a regular factorization matrix.
? nf = nfinit(y^2+1); ? nffactorback(nf, [3, y+1, [1,2]~], [1, 2, 3]) %2 = [12, -66]~ ? 3 * (I+1)^2 * (1+2*I)^3 %3 = 12 - 66*I
The library syntax is GEN nffactorback(GEN nf, GEN f, GEN e = NULL)
.
This routine is obsolete, use nfmodpr
and factormod
.
Factors the univariate polynomial Q modulo the prime ideal pr in
the number field nf. The coefficients of Q belong to the number
field (scalar, polmod, polynomial, even column vector) and the main variable
of nf must be of lower priority than that of Q (see
Section se:priority). The prime ideal pr is either in
idealprimedec
or (preferred) modprinit
format. The coefficients
of the polynomial factors are lifted to elements of nf:
? K = nfinit(y^2+1); ? P = idealprimedec(K, 3)[1]; ? nffactormod(K, x^2 + y*x + 18*y+1, P) %3 = [x + (2*y + 1) 1] [x + (2*y + 2) 1] ? P = nfmodprinit(K, P); \\ convert to nfmodprinit format ? nffactormod(K, x^2 + y*x + 18*y+1) %5 = [x + (2*y + 1) 1] [x + (2*y + 2) 1]
Same result, of course, here about 10% faster due to the precomputation.
The library syntax is GEN nffactormod(GEN nf, GEN Q, GEN pr)
.
Let nf be a
number field as output by nfinit
, and let aut be a Galois
automorphism of nf expressed by its image on the field generator
(such automorphisms can be found using nfgaloisconj
). The function
computes the action of the automorphism aut on the object x in the
number field; x can be a number field element, or an ideal (possibly
extended). Because of possible confusion with elements and ideals, other
vector or matrix arguments are forbidden.
? nf = nfinit(x^2+1); ? L = nfgaloisconj(nf) %2 = [-x, x]~ ? aut = L[1]; /* the nontrivial automorphism */ ? nfgaloisapply(nf, aut, x) %4 = Mod(-x, x^2 + 1) ? P = idealprimedec(nf,5); /* prime ideals above 5 */ ? nfgaloisapply(nf, aut, P[2]) == P[1] %6 = 0 \\ !!!! ? idealval(nf, nfgaloisapply(nf, aut, P[2]), P[1]) %7 = 1
The surprising failure of the equality test (%7
) is
due to the fact that although the corresponding prime ideals are equal, their
representations are not. (A prime ideal is specified by a uniformizer, and
there is no guarantee that applying automorphisms yields the same elements
as a direct idealprimedec
call.)
The automorphism can also be given as a column vector, representing the
image of Mod(x, nf.pol)
as an algebraic number. This last
representation is more efficient and should be preferred if a given
automorphism must be used in many such calls.
? nf = nfinit(x^3 - 37*x^2 + 74*x - 37); ? aut = nfgaloisconj(nf)[2]; \\ an automorphism in basistoalg form %2 = -31/11*x^2 + 1109/11*x - 925/11 ? AUT = nfalgtobasis(nf, aut); \\ same in algtobasis form %3 = [16, -6, 5]~ ? v = [1, 2, 3]~; nfgaloisapply(nf, aut, v) == nfgaloisapply(nf, AUT, v) %4 = 1 \\ same result... ? for (i=1,10^5, nfgaloisapply(nf, aut, v)) time = 463 ms. ? for (i=1,10^5, nfgaloisapply(nf, AUT, v)) time = 343 ms. \\ but the latter is faster
The library syntax is GEN galoisapply(GEN nf, GEN aut, GEN x)
.
nf being a number field as output by nfinit
, computes the
conjugates of a root r of the nonconstant polynomial x = nf[1]
expressed as polynomials in r. This also makes sense when the number field
is not Galois since some conjugates may lie in the field.
nf can simply be a polynomial.
If no flags or flag = 0, use a combination of flag 4 and 1 and the result is always complete. There is no point whatsoever in using the other flags.
If flag = 1, use nfroots
: a little slow, but guaranteed to work in
polynomial time.
If flag = 4, use galoisinit
: very fast, but only applies to (most)
Galois fields. If the field is Galois with weakly super-solvable Galois
group (see galoisinit
), return the complete list of automorphisms, else
only the identity element. If present, d is assumed to be a multiple of the
least common denominator of the conjugates expressed as polynomial in a root
of pol.
This routine can only compute ℚ-automorphisms, but it may be used to get K-automorphism for any base field K as follows:
rnfgaloisconj(nfK, R) = \\ K-automorphisms of L = K[X] / (R) { my(polabs, N,al,S, ala,k, vR); R *= Mod(1, nfK.pol); \\ convert coeffs to polmod elts of K vR = variable(R); al = Mod(variable(nfK.pol),nfK.pol); [polabs,ala,k] = rnfequation(nfK, R, 1); Rt = if(k==0,R,subst(R,vR,vR-al*k)); N = nfgaloisconj(polabs) % Rt; \\ Q-automorphisms of L S = select(s->subst(Rt, vR, Mod(s,Rt)) == 0, N); if (k==0, S, apply(s->subst(s,vR,vR+k*al)-k*al,S)); } K = nfinit(y^2 + 7); rnfgaloisconj(K, x^4 - y*x^3 - 3*x^2 + y*x + 1) \\ K-automorphisms of L
The library syntax is GEN galoisconj0(GEN nf, long flag, GEN d = NULL, long prec)
.
Use directly
GEN galoisconj(GEN nf, GEN d)
, corresponding to flag = 0, the others
only have historical interest.
Given nf a number field in nf or bnf format,
a t_VEC
Lpr of primes of nf and a t_VEC
Ld of
positive integers of the same length, a t_VECSMALL
pl of length
r1 the number of real places of nf, computes a polynomial with
coefficients in nf defining a cyclic extension of nf of
minimal degree satisfying certain local conditions:
* at the prime Lpr[i], the extension has local degree a multiple of Ld[i];
* at the i-th real place of nf, it is complex if pl[i] = -1 (no condition if pl[i] = 0).
The extension has degree the LCM of the local degrees. Currently, the degree
is restricted to be a prime power for the search, and to be prime for the
construction because of the rnfkummer
restrictions.
When nf is ℚ, prime integers are accepted instead of prid
structures. However, their primality is not checked and the behavior is
undefined if you provide a composite number.
Warning. If the number field nf does not contain the n-th roots of unity where n is the degree of the extension to be computed, the function triggers the computation of the bnf of nf(ζn), which may be costly.
? nf = nfinit(y^2-5); ? pr = idealprimedec(nf,13)[1]; ? pol = nfgrunwaldwang(nf, [pr], [2], [0,-1], 'x) %3 = x^2 + Mod(3/2*y + 13/2, y^2 - 5)
The library syntax is GEN nfgrunwaldwang(GEN nf, GEN Lpr, GEN Ld, GEN pl, long v = -1)
where v
is a variable number.
If pr is omitted,
compute the global quadratic Hilbert symbol (a,b) in nf, that
is 1 if x2 - a y2 - b z2 has a non trivial solution (x,y,z) in
nf, and -1 otherwise. Otherwise compute the local symbol modulo
the prime ideal pr, as output by idealprimedec
.
The library syntax is long nfhilbert0(GEN nf, GEN a, GEN b, GEN pr = NULL)
.
Also available is long nfhilbert(GEN nf,GEN a,GEN b)
(global
quadratic Hilbert symbol), where nf
is a true nf structure.
Given a pseudo-matrix (A,I), finds a pseudo-basis (B,J) in Hermite normal form of the module it generates. If flag is nonzero, also return the transformation matrix U such that AU = [0|B].
The library syntax is GEN nfhnf0(GEN nf, GEN x, long flag)
.
Also available:
GEN nfhnf(GEN nf, GEN x)
(flag = 0).
GEN rnfsimplifybasis(GEN bnf, GEN x)
simplifies the pseudo-basis
x = (A,I), returning a pseudo-basis (B,J). The ideals in the list J
are integral, primitive and either trivial (equal to the full ring of
integer) or nonprincipal.
Given a pseudo-matrix (A,I)
and an ideal detx which is contained in (read integral multiple of) the
determinant of (A,I), finds a pseudo-basis in Hermite normal form
of the module generated by (A,I). This avoids coefficient explosion.
detx can be computed using the function nfdetint
.
The library syntax is GEN nfhnfmod(GEN nf, GEN x, GEN detx)
.
pol being a nonconstant irreducible polynomial in ℚ[X],
preferably monic and integral, initializes a
number field (or nf) structure attached to the field K defined
by pol. As such, it's a technical object passed as the first argument
to most nf
xxx functions, but it contains some information which
may be directly useful. Access to this information via member
functions is preferred since the specific data organization given below
may change in the future. Currently, nf
is a row vector with 9
components:
nf[1] contains the polynomial pol (nf.pol
).
nf[2] contains [r1,r2] (nf.sign
, nf.r1
,
nf.r2
), the number of real and complex places of K.
nf[3] contains the discriminant d(K) (nf.disc
) of K.
nf[4] contains the index of nf[1] (nf.index
),
i.e. [ℤK : ℤ[θ]], where θ is any root of nf[1].
nf[5] is a vector containing 7 matrices M, G, roundG, T, MD, TI, MDI and a vector vP defined as follows:
* M is the (r1+r2) x n matrix whose columns represent the numerical values of the conjugates of the elements of the integral basis.
* G is an n x n matrix such that T2 = t G G, where T2 is the quadratic form T2(x) = ∑ |σ(x)|2, σ running over the embeddings of K into ℂ.
* roundG is a rescaled copy of G, rounded to nearest integers.
* T is the n x n matrix whose coefficients are Tr(ωiωj) where the ωi are the elements of the integral basis. Note also that det(T) is equal to the discriminant of the field K. Also, when understood as an ideal, the matrix T-1 generates the codifferent ideal.
* The columns of MD (nf.diff
) express a ℤ-basis
of the different of K on the integral basis.
* TI is equal to the primitive part of T-1, which has integral coefficients.
* MDI is a two-element representation (for faster
ideal product) of d(K) times the codifferent ideal
(nf.disc*nf.codiff
, which is an integral ideal). This is
used in idealinv
.
* vP is the list of prime divisors of the field discriminant,
i.e, the ramified primes (nf.p
); nfdiscfactors(nf)
is the
preferred way to access that information.
nf[6] is the vector containing the r1+r2 roots
(nf.roots
) of nf[1] corresponding to the r1+r2
embeddings of the number field into ℂ (the first r1 components are real,
the next r2 have positive imaginary part).
nf[7] is a ℤ-basis for dℤK, where d = [ℤK:ℤ(θ)],
expressed on the powers of θ. The multiplication by
d ensures that all polynomials have integral coefficients
and nf[7] / d (nf.zk
) is an integral basis for ℤK.
Its first element is guaranteed to be 1. This basis is LLL-reduced with
respect to T2 (strictly speaking, it is a permutation of such a basis,
due to the condition that the first element be 1).
nf[8] is the n x n integral matrix expressing the power basis in terms of the integral basis, and finally
nf[9] is the n x n2 matrix giving the multiplication table of the integral basis.
If a non monic or non integral polynomial is input, nfinit
will
transform it, and return a structure attached to the new (monic integral)
polynomial together with the attached change of variables, see flag = 3.
It is allowed, though not very useful given the existence of
nfnewprec
, to input a nf or a bnf instead of a polynomial.
It is also allowed to input a rnf, in which case an nf
structure
attached to the absolute defining polynomial polabs
is returned (flag is
then ignored).
? nf = nfinit(x^3 - 12); \\ initialize number field Q[X] / (X^3 - 12) ? nf.pol \\ defining polynomial %2 = x^3 - 12 ? nf.disc \\ field discriminant %3 = -972 ? nf.index \\ index of power basis order in maximal order %4 = 2 ? nf.zk \\ integer basis, lifted to Q[X] %5 = [1, x, 1/2*x^2] ? nf.sign \\ signature %6 = [1, 1] ? factor(abs(nf.disc )) \\ determines ramified primes %7 = [2 2] [3 5] ? idealfactor(nf, 2) %8 = [[2, [0, 0, -1]~, 3, 1, [0, 1, 0]~] 3] \\ 𝔭23
Huge discriminants, helping nfdisc.
In case pol has a huge discriminant which is difficult to factor, it is hard to compute from scratch the maximal order. The following special input formats are also accepted:
* [pol, B] where pol is a monic integral polynomial and
B is the lift of an integer basis, as would be computed by nfbasis
:
a vector of polynomials with first element 1 (implicitly modulo pol).
This is useful if the maximal order is known in advance.
* [pol, B, P] where pol and B are as above (a monic integral polynomial and the lift of an integer basis), and P is the list of ramified primes in the extension.
* [pol, listP
] where pol is a rational polynomial and
listP
specifies a list of primes as in nfbasis
. Instead of the
maximal order, nfinit
then computes
an order which is maximal at these particular primes as well as the primes
contained in the private prime table, see addprimes
. The result has
a good chance of being correct when the discriminant nf.disc
factors
completely over this set of primes but this is not guaranteed. The function
nfcertify
automates this:
? pol = polcompositum(x^5 - 101, polcyclo(7))[1]; ? nf = nfinit( [pol, 10^3] ); ? nfcertify(nf) %3 = []
A priori, nf.zk
defines an order which is only known
to be maximal at all primes ≤ 103 (no prime ≤ 103 divides
nf.index
). The certification step proves the correctness of the
computation. Had it failed, that particular nf
structure could
not have been trusted and may have caused routines using it to fail randomly.
One particular function that remains trustworthy in all cases is
idealprimedec
when applied to a prime included in the above list
of primes or, more generally, a prime not dividing any entry in
nfcertify
output.
In order to explain the meaning of flag, let P =
polredbest
(pol), a polynomial defining the same number field
obtained using the LLL algorithm on the lattice (ℤK, T2), which may be
equal to pol but is usually different and simpler. Binary digits of
flag mean:
* 1: return [nf,Mod
(a,P)], where nf is
nfinit
(P) and Mod
(a,P) = Mod
(x,pol) gives the
change of variables. If only this bit is set, the behaviour is useless since
we have P = pol.
* 2: return nfinit
(P).
Both flags are set automatically when pol is not monic or not
integral: first a linear change of variables is performed, to get a monic
integral polynomial, then polredbest
.
* 4: do not LLL-reduce nf.zk
, which saves time in large degrees,
you may expect to gain a factor 2 or so in degree n ≥ 100 or more, at
the expense of possibly slowing down later uses of the nf
structure. Use this flag if you only need basic arithmetic
(the nfelt*
, nfmodpr*
and ideal*
functions); or if you
expect the natural basis of the maximal order to contain small elements, this
will be the case for cyclotomic fields for instance. On the other hand,
functions involving LLL reduction of rank
n lattices should be avoided since each call will be about as costly as the
initial LLL reduction that the flag prevents and may become more costly
because of this missing initial reduction. In particular it is silly to use
this flag in addition to the first two, although GP will not protest.
? T = polcyclo(307); ? K = nfinit(T); time = 19,390 ms. ? a = idealhnf(K,1-x); time = 477ms ? idealfactor(K, a) time = 294ms ? Kno = nfinit(T, 4); time = 11,256 ms. ? ano = idealhnf(Kno,1-x); \\ no slowdown, even sligthly faster time = 460ms ? idealfactor(Kno, ano) time = 264ms ? nfinit(T, 2); \\ polredbest is very slow in high degree time = 4min, 34,870 ms. ? norml2(%.pol) == norml2(T) \\ and gains nothing here %9 = 1
The library syntax is GEN nfinit0(GEN pol, long flag, long prec)
.
Also available are
GEN nfinit(GEN x, long prec)
(flag = 0),
GEN nfinitred(GEN x, long prec)
(flag = 2),
GEN nfinitred2(GEN x, long prec)
(flag = 3).
Instead of the above hardcoded numerical flags in nfinit0
, one should
rather use an or-ed combination of
* nf_RED
: find a simpler defining polynomial,
* nf_ORIG
: also return the change of variable,
* nf_NOLLL
: do not LLL-reduce the maximal order ℤ-basis.
Returns 1 if x is an ideal in the number field nf, 0 otherwise.
The library syntax is long isideal(GEN nf, GEN x)
.
Let f and g define number fields, where f and g are irreducible
polynomials in ℚ[X] and nf structures as output by nfinit
.
If either f or g is not irreducible, the result is undefined.
Tests whether the number field f is conjugate to a subfield of the field
g. If not, the output is the integer 0; if it is, the output depends on
the value of flag:
* flag = 0 (default): return a vector of polynomials [a1,...,an] with rational coefficients, representing all distinct embeddings: we have g | f o ai for all i.
* flag = 1: return a single polynomial a representing a single embedding; this can be n times faster than the default when the embeddings have huge coefficients.
* flag = 2: return a vector of rational functions [r1,...,rn] whose denominators are coprime to g and such that ri % g is the polynomial ai from flag = 0. This variant is always faster than flag = 0 but produces results which are harder to use. If the denominators are hard to invert in ℚ[X]/(g), this may be even faster than flag = 1.
? T = x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10; ? U = x^3 + 3*x^2 + 3*x - 2 ? nfisincl(U, T) %3 = [24/179*x^5-27/179*x^4+80/179*x^3-234/179*x^2+380/179*x+94/179] ? a = nfisincl(U, T, 1) %4 = 24/179*x^5-27/179*x^4+80/179*x^3-234/179*x^2+380/179*x+94/179 ? subst(U, x, Mod(a,T)) %5 = Mod(0, x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10) ? nfisincl(U, T, 2) \\ a as a t_RFRAC %6 = [(2*x^3 - 3*x^2 + 2*x + 4)/(3*x^2 - 1)] ? (a - %[1]) % T %7 = 0 ? #nfisincl(x^2+1, T) \\ two embeddings %8 = 2 \\ same result with nf structures ? L = nfinit(T); K = nfinit(U); v = [a]; ? nfisincl(U, L) == v %10 = 1 ? nfisincl(K, T) == v %11 = 1 ? nfisincl(K, L) == v %12 = 1 \\ comparative bench: an nf is a little faster, esp. for the subfield ? B = 2000; ? for (i=1, B, nfisincl(U,T)) time = 1,364 ms. ? for (i=1, B, nfisincl(K,T)) time = 988 ms. ? for (i=1, B, nfisincl(U,L)) time = 1,341 ms. ? for (i=1, B, nfisincl(K,L)) time = 880 ms.
Using an nf structure for the tentative subfield is
faster if the structure is already available. On the other hand, the gain in
nfisincl
is usually not sufficient to make it worthwhile to initialize
only for that purpose.
? for (i=1, B, nfinit(U)) time = 590 ms.
A final more complicated example
? f = x^8 - 72*x^6 + 1944*x^4 - 30228*x^2 - 62100*x - 34749; ? g = nfsplitting(f); poldegree(g) %2 = 96 ? #nfisincl(f, g) time = 559 ms. %3 = 8 ? nfisincl(f,g,1); time = 172 ms. ? v = nfisincl(f,g,2); time = 199 ms. ? apply(x->poldegree(denominator(x)), v) %6 = [81, 81, 81, 81, 81, 81, 80, 81] ? v % g; time = 407 ms.
This final example shows that mapping rational functions to
ℚ[X]/(g) can be more costly than that the rest of the algorithm. Note that
nfsplitting
also admits a flag yielding an embedding.
The library syntax is GEN nfisincl0(GEN f, GEN g, long flag)
.
Also available is
GEN nfisisom(GEN a, GEN b)
(flag = 0).
As nfisincl
, but tests for isomorphism. More efficient if
f or g is a number field structure.
? f = x^6 + 30*x^5 + 495*x^4 + 1870*x^3 + 16317*x^2 - 22560*x + 59648; ? g = x^6 + 42*x^5 + 999*x^4 + 8966*x^3 + 36117*x^2 + 21768*x + 159332; ? h = x^6 + 30*x^5 + 351*x^4 + 2240*x^3 + 10311*x^2 + 35466*x + 58321; ? #nfisisom(f,g) \\ two isomorphisms %3 = 2 ? nfisisom(f,h) \\ not isomorphic %4 = 0 \\ comparative bench ? K = nfinit(f); L = nfinit(g); B = 10^3; ? for (i=1, B, nfisisom(f,g)) time = 6,124 ms. ? for (i=1, B, nfisisom(K,g)) time = 3,356 ms. ? for (i=1, B, nfisisom(f,L)) time = 3,204 ms. ? for (i=1, B, nfisisom(K,L)) time = 3,173 ms.
The function is usually very fast when the fields are nonisomorphic, whenever the fields can be distinguished via a simple invariant such as degree, signature or discriminant. It may be slower when the fields share all invariants, but still faster than computing actual isomorphisms:
\\ usually very fast when the answer is 'no': ? for (i=1, B, nfisisom(f,h)) time = 32 ms. \\ but not always ? u = x^6 + 12*x^5 + 6*x^4 - 377*x^3 - 714*x^2 + 5304*x + 15379 ? v = x^6 + 12*x^5 + 60*x^4 + 166*x^3 + 708*x^2 + 6600*x + 23353 ? nfisisom(u,v) %13 = 0 ? polsturm(u) == polsturm(v) %14 = 1 ? nfdisc(u) == nfdisc(v) %15 = 1 ? for(i=1,B, nfisisom(u,v)) time = 1,821 ms. ? K = nfinit(u); L = nfinit(v); ? for(i=1,B, nfisisom(K,v)) time = 232 ms.
The library syntax is GEN nfisisom(GEN f, GEN g)
.
Let nf be a nf structure attached to a number field K, let a ∈ K and let pr be a prid structure attached to a maximal ideal v. Return 1 if a is an n-th power in the completed local field Kv, and 0 otherwise.
? K = nfinit(y^2+1); ? P = idealprimedec(K,2)[1]; \\ the ramified prime above 2 ? nfislocalpower(K,P,-1, 2) \\ -1 is a square %3 = 1 ? nfislocalpower(K,P,-1, 4) \\ ... but not a 4-th power %4 = 0 ? nfislocalpower(K,P,2, 2) \\ 2 is not a square %5 = 0 ? Q = idealprimedec(K,5)[1]; \\ a prime above 5 ? nfislocalpower(K,Q, [0, 32]~, 30) \\ 32*I is locally a 30-th power %7 = 1
The library syntax is long nfislocalpower(GEN nf, GEN pr, GEN a, GEN n)
.
This function is obsolete, use nfmodpr
.
Kernel of the matrix a in ℤK/pr, where pr is in
modpr format (see nfmodprinit
).
The library syntax is GEN nfkermodpr(GEN nf, GEN x, GEN pr)
.
This function is normally useless in library mode. Project your
inputs to the residue field using nfM_to_FqM
, then work there.
Finds number fields (up to isomorphism) with Galois group of Galois closure isomorphic to G with s complex places. The number fields are given by polynomials. This function supports the following groups:
* degree 2: C2 = 2T1;
* degree 3: C3 = 3T1 and S3 = 3T2;
* degree 4: C4 = 4T1, V4 = 4T2, D4 = 4T3, A4 = 4T4 and S4 = 4T5;
* degree 5: C5 = 5T1, D5 = 5T2, F5 = M20 = 5T3 and A5 = 5T4;
* degree 6: C6 = 6T1, S3(6) = D6(6) = 6T2, D6(12) = 6T3, A4(6) = 6T4, S3 x C3 = 6T5, A4(6) x C2 = 6T6, S4(6)+ = 6T7, S4(6)− = 6T8, S32 = 6T9, C32:C4 = 6T10, S4(6) x C2 = 6T11, A5(6) = PSL2(5) = 6T12 and C32:D4 = 6T13;
* degree 7: C7 = 7T1, D7 = 7T2, M21 = 7T3 and M42 = 7T4;
* degree 9: C9 = 9T1, C3 x C3 = 9T2 and D9 = 9T3;
* degree ℓ with ℓ prime: Cℓ = ℓ T1 and Dℓ = ℓ T2.
The groups A5 and A5(6) require the optional package
nflistdata
.
In addition, if N is a polynomial, all transitive subgroups of Sn with n ≤ 15, as well as alternating groups An and the full symmetric group Sn for all n (see below for details and explanations).
The groups are coded as [n,k] using the nTk
format where n is the
degree and k is the T-number, the index in the classification of
transitive subgroups of Sn.
Alternatively, the groups Cn, Dn, An, Sn,
V4, F5 = M20, M21 and M42 can be input as
character strings exactly as written, lifting subscripts; for instance
"S4"
or "M21"
. If the group is not recognized or is
unsupported the function raises an exception.
The number fields are computed on the fly (and not from a preexisting table)
using a variety of algorithms, with the exception of A5 and A5(6)
which are obtained by table lookup.
The algorithms are recursive and use the following ingredients: build
distinguished subfields (or resolvent fields in Galois closures) of smaller
degrees, use class field theory to build abelian extensions over a known
base, select subfields using Galois theory. Because of our use of class
field theory, and ultimately bnfinit
, all results depend on the GRH in
degree n > 3.
To avoid wasting time, the output polynomials defining the number fields are
usually not the simplest possible, use polredbest
or polredabs
to reduce them.
The non-negative integer s specifies the number of complex places, between 0 and n/2. Additional supported values are:
* s = -1 (default) all signatures;
* s = -2 all signatures, given by increasing number of complex places; in degree n, this means a vector with 1 + floor(n/2) components: the i-th entry corresponds to s = i - 1.
If the irreducible monic polynomial F ∈ ℤ[X] is specified, gives only
number fields having ℚ[X]/(F) as a subfield, or in the case of
S3, Dℓ, A4, S4, F5, M21 and M42,
as a resolvent field (see also the function nfresolvent
for these cases).
The parameter N can be the following:
* a positive integer: finds all fields with absolute discriminant N (recall that the discriminant over ℚ is (-1)s N).
* a pair of non-negative real numbers [a,b] specifying a real interval: finds all fields with absolute value of discriminant between a and b. For most Galois groups, this is faster than iterating on individual N.
* omitted (default): a few fields of small discriminant (not always those with smallest absolute discriminant) are output with given G and s; usually about 10, less if too difficult to find. The parameter F is ignored.
* a polynomial with main variable, say t, of priority lower than x.
The program outputs a regular polynomial in ℚ(t)[x] (in fact in
ℤ[x,t]) with the given Galois group. By Hilbert irreducibility, almost all
specializations of t will give suitable polynomials. The parameters s and
F are ignored. This is implemented for all transitive subgroups of
Sn with n ≤ 15 as well as for the alternating and symmetric groups
An and Sn for all n.
Polynomials for An were inspired by J.-F. Mestre, a few polynomials in
degree ≤ 8 come from G. W. Smith, "Some polynomials over ℚ(t) and
their Galois groups", Math. Comp., 69 (230), 1999, pp. 775–796
most others in degree ≤ 11 were provided by J. Klüners and G. Malle
(see G. Malle and B. H. Matzat, Inverse Galois Theory, Springer,
1999) and T. Dokchitser completed the list up to degree 15. But for
An and Sn, subgroups of Sn for n > 7 require the optional
nflistdata
package.
Complexity. : For a positive integer N, the complexity is subexponential in log N (and involves factoring N). For an interval [a,b], the complexity is roughly as follows, ignoring terms which are subexponential in log b. It is usually linear in the output size.
* Cn: O(b1/φ(n)) for n = 2, 4, 6, 9 or any odd prime;
* Dn: O(b2/φ(n)) for n = 4 or any odd prime;
* V4, A4: O(b1/2), S4: O(b); N.B. The subexponential terms are expensive for A4 and S4.
* M20: O(b).
* S4(6)−, S4(6)+ A4(6) x C2, S3 x S3, S4(6) x C2 : O(b), D6(12), A4(6), S3(6), S3 x C3, C32:C4: O(b1/2).
* M21, M42: O(b).
* C3 x C3: O(b1/3), D9: O(b5/12).
? #nflist("S3", [1, 10^5]) \\ S3 cubic fields %1 = 21794 ? #nflist("S3", [1, 10^5], 0) \\ real S3 cubic fields (0 complex place) %2 = 4753 ? #nflist("S3", [1, 10^5], 1) \\ complex cubic fields (1 complex place) %3 = 17041 ? v = nflist("S3", [1, 10^5], -2); apply(length,v) %4 = [4753, 17041] ? nflist("S4") \\ a few S4 fields %5 = [x^4 + 12*x^2 - 8*x + 16, x^4 - 2*x^2 - 8*x + 25, ...] ? nflist("S4",,0) \\ a few real S4 fields %6 = [x^4 - 52*x^2 - 56*x + 48, x^4 - 26*x^2 - 8*x + 1, ...] ? nflist("S4",,-2) \\ a few real S4 fields, by signature %7 = [[x^4 - 52*x^2 - 56*x + 48, ...], [x^4 - 8*x - 16, ... ], [x^4 + 138*x^2 - 8*x + 4541, ...]] ? nflist("S3",,,x^2+23) \\ a few cubic fields with resolvent Q(sqrt(-23)) %8 = [x^3 + x + 1, x^3 + 2*x + 1, ...] ? nflist("C3", 3969) \\ C3 fields of given discriminant %9 = [x^3 - 21*x + 28, x^3 - 21*x - 35] ? nflist([3,1], 3969) \\ C3 fields, using nTt label %10 = [x^3 - 21*x + 28, x^3 - 21*x - 35] ? P = nflist([8,12],t) \\ geometric 8T12 polynomial %11 = x^8 + (-t^2 - 803)*x^6 + (264*t^2 + 165528)*x^4 + (-2064*t^2 - 1724976)*x^2 + 4096*t^2 ? polgalois(subst(P, t, 11)) %12 = [24, 1, 12, "2A4(8)=[2]A(4)=SL(2,3)"] ? nflist("S11") *** at top-level: nflist("S11") *** ^ — — — — - *** nflist: unsupported group (S11). Use one of "C1"=[1,1]; "C2"=[2,1]; "C3"=[3,1], "S3"=[3,2]; "C4"=[4,1], "V4"=[4,2], "D4"=[4,3], "A4"=[4,4], "S4"=[4,5]; "C5"=[5,1], "D5"=[5,2], "F5"="M20"=[5,3], "A5"=[5,4]; "C6"=[6,1], "D6"=[6,2], [6,3], ..., [6,13]; "C7"=[7,1], "D7"=[7,2], "M21"=[7,3], "M42"=[7,4]; "C9"=[9,1], [9,2], "D9"=[9,3]." Also supported are "Cp"=[p,1] and "Dp"=[p,2] for any odd prime p. ? nflist("S25", 't) %13 = x^25 + x*t + 1
The library syntax is GEN nflist(GEN G, GEN N = NULL, long s, GEN F = NULL)
.
Map x to a t_FFELT
in the residue field modulo pr.
The argument pr is either a maximal ideal in idealprimedec
format or, preferably, a modpr structure from nfmodprinit
. The
function nfmodprlift
allows to lift back to ℤK.
Note that the function applies to number field elements and not to
vector / matrices / polynomials of such. Use apply
to convert
recursive structures.
? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K, P, 't); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, t, 2*t + 1] ? %[1].mod %6 = t^2 + 3*t + 4 ? K.index %7 = 125
For clarity, we represent elements in the residue
field 𝔽5[t]/(T) as polynomials in the variable t. Whenever the
underlying rational prime does not divide K.index
, it is actually
the case that t is the reduction of y in ℚ[y]/(K.pol
)
modulo an irreducible factor of K.pol
over 𝔽p. In the above
example, 5 divides the index and t is actually the reduction of y/5.
The library syntax is GEN nfmodpr(GEN nf, GEN x, GEN pr)
.
Transforms the prime ideal pr into modpr
format necessary
for all operations modulo pr in the number field nf.
The functions nfmodpr
and nfmodprlift
allow to project
to and lift from the residue field. The variable v is used to display
finite field elements (see ffgen
).
? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K, P, 't); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, t, 2*t + 1] ? %[1].mod %6 = t^2 + 3*t + 4 ? K.index %7 = 125
For clarity, we represent elements in the residue
field 𝔽5[t]/(T) as polynomials in the variable t. Whenever the
underlying rational prime does not divide K.index
, it is actually
the case that t is the reduction of y in ℚ[y]/(K.pol
)
modulo an irreducible factor of K.pol
over 𝔽p. In the above
example, 5 divides the index and t is actually the reduction of y/5.
The library syntax is GEN nfmodprinit0(GEN nf, GEN pr, long v) = -1)
where v)
is a variable number.
Lift the t_FFELT
x (from nfmodpr
) in the residue field
modulo pr to the ring of integers. Vectors and matrices are also
supported. For polynomials, use apply
and the present function.
The argument pr is either a maximal ideal in idealprimedec
format or, preferably, a modpr structure from nfmodprinit
.
There are no compatibility checks to try and decide whether x is attached
the same residue field as defined by pr: the result is undefined
if not.
The function nfmodpr
allows to reduce to the residue field.
? K = nfinit(y^3-250); ? P = idealprimedec(K, 5)[2]; ? modP = nfmodprinit(K,P); ? K.zk %4 = [1, 1/5*y, 1/25*y^2] ? apply(t->nfmodpr(K,t,modP), K.zk) %5 = [1, y, 2*y + 1] ? nfmodprlift(K, %, modP) %6 = [1, 1/5*y, 2/5*y + 1] ? nfeltval(K, %[3] - K.zk[3], P) %7 = 1
The library syntax is GEN nfmodprlift(GEN nf, GEN x, GEN pr)
.
Transforms the number field nf
into the corresponding data using current (usually larger) precision. This
function works as expected if nf is in fact a bnf, a bnr
or a rnf (update structure to current precision). If the original
bnf structure was not computed by bnfinit(,1)
, then
this may be quite slow and even fail: many
generators of principal ideals have to be computed and the algorithm may
fail because the accuracy is not sufficient to bootstrap the
required generators and fundamental units.
The library syntax is GEN nfnewprec(GEN nf, long prec)
.
See also GEN bnfnewprec(GEN bnf, long prec)
and
GEN bnrnewprec(GEN bnr, long prec)
.
Given a polynomial T with coefficients in the number field nf, returns the number of real roots of the s(T) where s runs through the real embeddings of the field specified by optional argument pl:
* pl omitted: all r1 real places;
* pl an integer between 1 and r1: the embedding attached to
the i-th real root of nf.pol
, i.e. nf.roots[i]
;
* pl a vector or t_VECSMALL
: the embeddings
attached to the pl[i]-th real roots of nf.pol
.
? nf = nfinit('y^2 - 2); ? nf.sign %2 = [2, 0] ? nf.roots %3 = [-1.414..., 1.414...] ? T = x^2 + 'y; ? nfpolsturm(nf, T, 1) \\ subst(T,y,sqrt(2)) has two real roots %5 = 2 ? nfpolsturm(nf, T, 2) \\ subst(T,y,-sqrt(2)) has no real root %6 = 0 ? nfpolsturm(nf, T) \\ all embeddings together %7 = [2, 0] ? nfpolsturm(nf, T, [2,1]) \\ second then first embedding %8 = [0, 2] ? nfpolsturm(nf, x^3) \\ number of distinct roots ! %9 = [1, 1] ? nfpolsturm(nf, x, 6) \\ there are only 2 real embeddings ! *** at top-level: nfpolsturm(nf,x,6) *** ^ — — — — — -- *** nfpolsturm: domain error in nfpolsturm: index > 2
The library syntax is GEN nfpolsturm(GEN nf, GEN T, GEN pl = NULL)
.
Let pol
be an irreducible integral polynomial defining a number
field K with Galois closure ~{K}. This function is limited to the
Galois groups supported by nflist
; in the following ℓ denotes an
odd prime. If Gal(~{K}/ℚ) is Dℓ, A4, S4,
F5 (M20), A5, M21 or M42,
returns a polynomial R defining the corresponding resolvent field (quadratic
for Dℓ, cyclic cubic for A4 and M21, noncyclic cubic for
S4, cyclic quartic for F5, A5(6) sextic for A5, and cyclic
sextic for M42). In the A5(6) case, returns the A5 field of
which it is the resolvent. Otherwise, gives a "canonical" subfield, or 0
if the Galois group is not supported.
The binary digits of flag correspond to 1: returns a pair [R,f] where f is a "conductor" whose definition is specific to each group and given below; 2: returns all "canonical" subfields.
Let D be the discriminant of the resolvent field nfdisc
(R):
* In cases Cℓ, Dℓ, A4, or S4, disc(K) = (Df2)m with m = (ℓ-1)/2 in the first two cases, and 1 in the last two.
* In cases where K is abelian over the resolvent subfield, the conductor of the relative extension.
* In case F5, disc(K) = Df4 if f > 0 or 52Df4 if f < 0.
* In cases M21 or M42, disc(K) = Dmf6 if f > 0 or 73Dmf6 if f < 0, where m = 2 for M21 and m = 1 for M42.
* In cases A5 and A5(6), flag is currently ignored.
? pol = x^6-3*x^5+7*x^4-9*x^3+7*x^2-3*x+1; \\ Galois closure D6 ? nfresolvent(pol) %2 = x^3 + x - 1 ? nfresolvent(pol,1) %3 = [x^3 + x - 1, [[31, 21, 3; 0, 1, 0; 0, 0, 1], [1]]]
The library syntax is GEN nfresolvent(GEN pol, long flag)
.
Roots of the polynomial x in the
number field nf given by nfinit
without multiplicity (in ℚ
if nf is omitted). x has coefficients in the number field (scalar,
polmod, polynomial, column vector). The main variable of nf must be
of lower priority than that of x (see Section se:priority). However if the
coefficients of the number field occur explicitly (as polmods) as
coefficients of x, the variable of these polmods must be the same as
the main variable of t (see nffactor
).
It is possible to input a defining polynomial for nf
instead, but this is in general less efficient since parts of an nf
structure will then be computed internally. This is useful in two
situations: when you do not need the nf
elsewhere, or when you cannot
initialize an nf
due to integer factorization difficulties when
attempting to compute the field discriminant and maximal order.
Caveat. nfinit([T, listP])
allows to compute in polynomial
time a conditional nf structure, which sets nf.zk
to an order
which is not guaranteed to be maximal at all primes. Always either use
nfcertify
first (which may not run in polynomial time) or make sure
to input nf.pol
instead of the conditional nf: nfroots
is
able to recover in polynomial time in this case, instead of potentially
missing a factor.
The library syntax is GEN nfroots(GEN nf = NULL, GEN x)
.
See also GEN nfrootsQ(GEN x)
,
corresponding to nf
= NULL
.
Returns a two-component vector [w,z] where w is the number of roots of unity in the number field nf, and z is a primitive w-th root of unity. It is possible to input a defining polynomial for nf instead.
? K = nfinit(polcyclo(11)); ? nfrootsof1(K) %2 = [22, [0, 0, 0, 0, 0, -1, 0, 0, 0, 0]~] ? z = nfbasistoalg(K, %[2]) \\ in algebraic form %3 = Mod(-x^5, x^10 + x^9 + x^8 + x^7 + x^6 + x^5 + x^4 + x^3 + x^2 + x + 1) ? [lift(z^11), lift(z^2)] \\ proves that the order of z is 22 %4 = [-1, -x^9 - x^8 - x^7 - x^6 - x^5 - x^4 - x^3 - x^2 - x - 1]
This function guesses the number w as the gcd of the #k(v)* for unramified v above odd primes, then computes the roots in nf of the w-th cyclotomic polynomial. The algorithm is polynomial time with respect to the field degree and the bitsize of the multiplication table in nf (both of them polynomially bounded in terms of the size of the discriminant). Fields of degree up to 100 or so should require less than one minute.
The library syntax is GEN nfrootsof1(GEN nf)
.
Given a torsion ℤK-module x attached to the square integral invertible pseudo-matrix (A,I,J), returns an ideal list D = [d1,...,dn] which is the Smith normal form of x. In other words, x is isomorphic to ℤK/d1⨁ ...⨁ ℤK/dn and di divides di-1 for i ≥ 2. If flag is nonzero return [D,U,V], where UAV is the identity.
See Section se:ZKmodules for the definition of integral pseudo-matrix; briefly, it is input as a 3-component row vector [A,I,J] where I = [b1,...,bn] and J = [a1,...,an] are two ideal lists, and A is a square n x n matrix with columns (A1,...,An), seen as elements in Kn (with canonical basis (e1,...,en)). This data defines the ℤK module x given by (b1e1⨁ ...⨁ bnen) / (a1A1⨁ ...⨁ anAn) , The integrality condition is ai,j ∈ bi aj-1 for all i,j. If it is not satisfied, then the di will not be integral. Note that every finitely generated torsion module is isomorphic to a module of this form and even with bi = ZK for all i.
The library syntax is GEN nfsnf0(GEN nf, GEN x, long flag)
.
Also available:
GEN nfsnf(GEN nf, GEN x)
(flag = 0).
This function is obsolete, use nfmodpr
.
Let P be a prime ideal in modpr format (see nfmodprinit
),
let a be a matrix, invertible over the residue field, and let b be
a column vector or matrix. This function returns a solution of a.x =
b; the coefficients of x are lifted to nf elements.
? K = nfinit(y^2+1); ? P = idealprimedec(K, 3)[1]; ? P = nfmodprinit(K, P); ? a = [y+1, y; y, 0]; b = [1, y]~ ? nfsolvemodpr(K, a,b, P) %5 = [1, 2]~
The library syntax is GEN nfsolvemodpr(GEN nf, GEN a, GEN b, GEN P)
.
This function is normally useless in library mode. Project your
inputs to the residue field using nfM_to_FqM
, then work there.
Defining polynomial S over ℚ for the splitting field of
P ∈ ℚ[x], that is the smallest field over which P is totally
split. If irreducible, the polynomial P can also be given by a nf
structure, which is more efficient. If d is given, it must be a multiple of
the splitting field degree. Note that if P is reducible the splitting field
degree can be smaller than the degree of P.
If flag is non-zero, we assume P to be monic, integral and irreducible and the return value depends on flag:
* flag = 1: return [S,C] where S is as before and C is an
embedding of ℚ[x]/(P) in its splitting field given by a polynomial
(implicitly modulo S, as in nfisincl
).
* flag = 2: return [S,C] where C is vector of rational functions whose image in ℚ[x]/(S) yields the embedding; this avoids inverting the denominator, which is costly. when the degree of the splitting field is huge.
* flag = 3: return [S, v, p] a data structure allowing to quickly
compute the Galois group of the splitting field, which is used by
galoissplittinginit
; more precisely, p is a prime splitting
completely in the splitting field and v is a vector with deg S
elements describing the automorphisms of S acting on the roots
of S modulo p.
? K = nfinit(x^3 - 2); ? nfsplitting(K) %2 = x^6 + 108 ? nfsplitting(x^8 - 2) %3 = x^16 + 272*x^8 + 64 ? S = nfsplitting(x^6 - 8) \\ reducible %4 = x^4 + 2*x^2 + 4 ? lift(nfroots(subst(S,x,a),x^6-8)) %5 = [-a, a, -1/2*a^3 - a, -1/2*a^3, 1/2*a^3, 1/2*a^3 + a] ? P = x^8-2; ? [S,C] = nfsplitting(P,,1) %7 = [x^16 + 272*x^8 + 64, -7/768*x^13 - 239/96*x^5 + 1/2*x] ? subst(P, x, Mod(C,S)) %8 = Mod(0, x^16 + 272*x^8 + 64)
Specifying the degree d of the splitting field can make the computation faster; if d is not a multiple of the true degree, it will be ignored with a warning.
? nfsplitting(x^17-123); time = 3,607 ms. ? poldegree(%) %2 = 272 ? nfsplitting(x^17-123,272); time = 150 ms. ? nfsplitting(x^17-123,273); *** nfsplitting: Warning: ignoring incorrect degree bound 273 time = 3,611 ms.
The complexity of the algorithm is polynomial in the degree d of the
splitting field and the bitsize of T; if d is large the result will
likely be unusable, e.g. nfinit
will not be an option:
? nfsplitting(x^6-x-1) [... degree 720 polynomial deleted ...] time = 11,020 ms.
Variant: Also available is
GEN nfsplitting(GEN T, GEN D)
for flag = 0.
The library syntax is GEN nfsplitting0(GEN P, GEN d = NULL, long fl)
.
Finds all subfields of degree d of the number field defined by the (monic, integral) polynomial pol (all subfields if d is null or omitted). The result is a vector of subfields, each being given by [g,h] (default) or simply g (flag = 1), where g is an absolute equation and h expresses one of the roots of g in terms of the root x of the polynomial defining nf. This routine uses
* Allombert's galoissubfields
when nf is Galois (with weakly
supersolvable Galois group).
* Klüners's or van Hoeij-Klüners-Novocin algorithm in the general case. The latter runs in polynomial time and is generally superior unless there exists a small unramified prime p such that pol has few irreducible factors modulo p.
An input of the form [nf, fa]
is also allowed, where fa
is the
factorisation of nf.pol over nf, expressed as a famat of
polynomials with coefficients in the variable of nf
, in which case the
van Hoeij-Klüners-Novocin algorithm is used.
? pol = x^4 - x^3 - x^2 + x + 1; ? nfsubfields(pol) %2 = [[x, 0], [x^2 - x + 1, x^3 - x^2 + 1], [x^4 - x^3 - x^2 + x + 1, x]] ? nfsubfields(pol,,1) %2 = [x, x^2 - x + 1, x^4 - x^3 - x^2 + x + 1] ? y=varhigher("y"); fa = nffactor(pol,subst(pol,x,y)); ? #nfsubfields([pol,fa]) %5 = 3
The library syntax is GEN nfsubfields0(GEN pol, long d, long flag)
.
Also available is GEN nfsubfields(GEN nf, long d)
, corresponding
to flag = 0.
Computes the maximal CM subfield of nf. Returns 0 if nf does
not have a CM subfield, otherwise returns [g,h] (default) or g (flag = 1)
where g is an absolute equation and h expresses a root of g in terms of
the generator of nf.
Moreover, the CM involution is given by X mod g(X) ⟼
-X mod g(X),
i.e. X mod g(X) is a totally imaginary element.
An input of the form [nf, fa]
is also allowed, where fa
is the
factorisation of nf.pol over nf, and nf is also allowed to
be a monic defining polynomial for the number field.
? nf = nfinit(x^8 + 20*x^6 + 10*x^4 - 4*x^2 + 9); ? nfsubfieldscm(nf) %2 = [x^4 + 4480*x^2 + 3612672, 3*x^5 + 58*x^3 + 5*x] ? pol = y^16-8*y^14+29*y^12-60*y^10+74*y^8-48*y^6+8*y^4+4*y^2+1; ? fa = nffactor(pol, subst(pol,y,x)); ? nfsubfieldscm([pol,fa]) %5 = [y^8 + ... , ...]
The library syntax is GEN nfsubfieldscm(GEN nf, long flag)
.
Computes the list of maximal subfields of nf. The result is a vector
as in nfsubfields
.
An input of the form [nf, fa]
is also allowed, where fa
is the
factorisation of nf.pol over nf, and nf is also allowed to
be a monic defining polynomial for the number field.
The library syntax is GEN nfsubfieldsmax(GEN nf, long flag)
.
Let nf be attached to a number field K, let v be a vector of
elements of K, not all of them 0, seen as element of the projective
space of dimension #v - 1
. Return the absolute logarithmic Weil height
of that element, which does not depend on the number field used to compute it.
When the entries of v are rational, the height is
log(normlp(v / content(v), oo))
.
? v = [1, 2, -3, 101]; Q = nfinit(x); Qi = nfinit(x^2 + 1); ? exponent(nfweilheight(Q, v) - log(101)) %2 = -125 ? exponent(nfweilheight(Qi, v) - log(101)) %3 = -125
The library syntax is GEN nfweilheight(GEN nf, GEN v, long prec)
.
P and Q being squarefree polynomials in ℤ[X] in the same variable, outputs the simple factors of the étale ℚ-algebra A = ℚ(X, Y) / (P(X), Q(Y)). The factors are given by a list of polynomials R in ℤ[X], attached to the number field ℚ(X)/ (R), and sorted by increasing degree (with respect to lexicographic ordering for factors of equal degrees). Returns an error if one of the polynomials is not squarefree.
Note that it is more efficient to reduce to the case where P and Q are irreducible first. The routine will not perform this for you, since it may be expensive, and the inputs are irreducible in most applications anyway. In this case, there will be a single factor R if and only if the number fields defined by P and Q are linearly disjoint (their intersection is ℚ).
Assuming P is irreducible (of smaller degree than Q for efficiency), it is in general much faster to proceed as follows
nf = nfinit(P); L = nffactor(nf, Q)[,1]; vector(#L, i, rnfequation(nf, L[i]))
to obtain the same result. If you are only interested in the degrees of the
simple factors, the rnfequation
instruction can be replaced by a
trivial poldegree(P) * poldegree(L[i])
.
The binary digits of flag mean
1: outputs a vector of 4-component vectors [R,a,b,k], where R ranges through the list of all possible compositums as above, and a (resp. b) expresses the root of P (resp. Q) as an element of ℚ(X)/(R). Finally, k is a small integer such that b + ka = X modulo R.
2: assume that P and Q define number fields which are linearly disjoint: both polynomials are irreducible and the corresponding number fields have no common subfield besides ℚ. This allows to save a costly factorization over ℚ. In this case return the single simple factor instead of a vector with one element.
A compositum is often defined by a complicated polynomial, which it is advisable to reduce before further work. Here is an example involving the field ℚ(ζ5, 51/5):
? L = polcompositum(x^5 - 5, polcyclo(5), 1); \\ list of [R,a,b,k]
? [R, a] = L[1]; \\ pick the single factor, extract R,a (ignore b,k)
? R \\ defines the compositum
%3 = x^20 + 5*x^19 + 15*x^18 + 35*x^17 + 70*x^16 + 141*x^15 + 260*x^14\
+ 355*x^13 + 95*x^12 - 1460*x^11 - 3279*x^10 - 3660*x^9 - 2005*x^8 \
+ 705*x^7 + 9210*x^6 + 13506*x^5 + 7145*x^4 - 2740*x^3 + 1040*x^2 \
- 320*x + 256
? a^5 - 5 \\ a fifth root of 5
%4 = 0
? [T, X] = polredbest(R, 1);
? T \\ simpler defining polynomial for ℚ[x]/(R)
%6 = x^20 + 25*x^10 + 5
? X \\ root of R in ℚ[y]/(T(y))
%7 = Mod(-1/11*x^15 - 1/11*x^14 + 1/22*x^10 - 47/22*x^5 - 29/11*x^4 + 7/22,\
x^20 + 25*x^10 + 5)
? a = subst(a.pol, 'x, X) \\ a
in the new coordinates
%8 = Mod(1/11*x^14 + 29/11*x^4, x^20 + 25*x^10 + 5)
? a^5 - 5
%9 = 0
In the above example, x5-5 and the 5-th cyclotomic polynomial are irreducible over ℚ; they have coprime degrees so define linearly disjoint extensions and we could have started by
? [R,a] = polcompositum(x^5 - 5, polcyclo(5), 3); \\ [R,a,b,k]
The library syntax is GEN polcompositum0(GEN P, GEN Q, long flag)
.
Also available are
GEN compositum(GEN P, GEN Q)
(flag = 0) and
GEN compositum2(GEN P, GEN Q)
(flag = 1).
Galois group of the nonconstant
polynomial T ∈ ℚ[X]. In the present version 2.17.0, T must be irreducible
and the degree d of T must be less than or equal to 7. If the
galdata
package has been installed, degrees 8, 9, 10 and 11 are also
implemented. By definition, if K = ℚ[x]/(T), this computes the action of
the Galois group of the Galois closure of K on the d distinct roots of
T, up to conjugacy (corresponding to different root orderings).
The output is a 4-component vector [n,s,k,name] with the following meaning: n is the cardinality of the group, s is its signature (s = 1 if the group is a subgroup of the alternating group Ad, s = -1 otherwise) and name is a character string containing name of the transitive group according to the GAP 4 transitive groups library by Alexander Hulpke.
k is more arbitrary and the choice made up to version 2.2.3 of PARI is rather unfortunate: for d > 7, k is the numbering of the group among all transitive subgroups of Sd, as given in "The transitive groups of degree up to eleven", G. Butler and J. McKay, Communications in Algebra, vol. 11, 1983, pp. 863–911 (group k is denoted Tk there). And for d ≤ 7, it was ad hoc, so as to ensure that a given triple would denote a unique group. Specifically, for polynomials of degree d ≤ 7, the groups are coded as follows, using standard notations
In degree 1: S1 = [1,1,1].
In degree 2: S2 = [2,-1,1].
In degree 3: A3 = C3 = [3,1,1], S3 = [6,-1,1].
In degree 4: C4 = [4,-1,1], V4 = [4,1,1], D4 = [8,-1,1], A4 = [12,1,1], S4 = [24,-1,1].
In degree 5: C5 = [5,1,1], D5 = [10,1,1], M20 = [20,-1,1], A5 = [60,1,1], S5 = [120,-1,1].
In degree 6: C6 = [6,-1,1], S3 = [6,-1,2], D6 = [12,-1,1], A4 = [12,1,1], G18 = [18,-1,1], S4− = [24,-1,1], A4 x C2 = [24,-1,2], S4+ = [24,1,1], G36− = [36,-1,1], G36+ = [36,1,1], S4 x C2 = [48,-1,1], A5 = PSL2(5) = [60,1,1], G72 = [72,-1,1], S5 = PGL2(5) = [120,-1,1], A6 = [360,1,1], S6 = [720,-1,1].
In degree 7: C7 = [7,1,1], D7 = [14,-1,1], M21 = [21,1,1], M42 = [42,-1,1], PSL2(7) = PSL3(2) = [168,1,1], A7 = [2520,1,1], S7 = [5040,-1,1].
This is deprecated and obsolete, but for reasons of backward compatibility,
we cannot change this behavior yet. So you can use the default
new_galois_format
to switch to a consistent naming scheme, namely k is
always the standard numbering of the group among all transitive subgroups of
Sn. If this default is in effect, the above groups will be coded as:
In degree 1: S1 = [1,1,1].
In degree 2: S2 = [2,-1,1].
In degree 3: A3 = C3 = [3,1,1], S3 = [6,-1,2].
In degree 4: C4 = [4,-1,1], V4 = [4,1,2], D4 = [8,-1,3], A4 = [12,1,4], S4 = [24,-1,5].
In degree 5: C5 = [5,1,1], D5 = [10,1,2], M20 = [20,-1,3], A5 = [60,1,4], S5 = [120,-1,5].
In degree 6: C6 = [6,-1,1], S3 = [6,-1,2], D6 = [12,-1,3], A4 = [12,1,4], G18 = [18,-1,5], A4 x C2 = [24,-1,6], S4+ = [24,1,7], S4− = [24,-1,8], G36− = [36,-1,9], G36+ = [36,1,10], S4 x C2 = [48,-1,11], A5 = PSL2(5) = [60,1,12], G72 = [72,-1,13], S5 = PGL2(5) = [120,-1,14], A6 = [360,1,15], S6 = [720,-1,16].
In degree 7: C7 = [7,1,1], D7 = [14,-1,2], M21 = [21,1,3], M42 = [42,-1,4], PSL2(7) = PSL3(2) = [168,1,5], A7 = [2520,1,6], S7 = [5040,-1,7].
Warning. The method used is that of resolvent polynomials and is sensitive to the current precision. The precision is updated internally but, in very rare cases, a wrong result may be returned if the initial precision was not sufficient.
The library syntax is GEN polgalois(GEN T, long prec)
.
To enable the new format in library mode,
set the global variable new_galois_format
to 1.
This function is deprecated, use polredbest
instead.
Finds polynomials with reasonably small coefficients defining subfields of
the number field defined by T. One of the polynomials always defines ℚ
(hence has degree 1), and another always defines the same number field
as T if T is irreducible.
All T accepted by nfinit
are also allowed here;
in particular, the format [T, listP]
is recommended, e.g. with
listP
= 105 or a vector containing all ramified primes. Otherwise,
the maximal order of ℚ[x]/(T) must be computed.
The following binary digits of flag are significant:
1: Possibly use a suborder of the maximal order. The
primes dividing the index of the order chosen are larger than
primelimit
or divide integers stored in the addprimes
table.
This flag is deprecated, the [T, listP]
format is more
flexible.
2: gives also elements. The result is a two-column matrix, the first column giving primitive elements defining these subfields, the second giving the corresponding minimal polynomials.
? M = polred(x^4 + 8, 2) %1 = [ 1 x - 1] [ 1/2*x^2 + 1 x^2 - 2*x + 3] [-1/2*x^2 + 1 x^2 - 2*x + 3] [ 1/2*x^2 x^2 + 2] [ 1/4*x^3 x^4 + 2] ? minpoly(Mod(M[4,1], x^4+8)) %2 = x^2 + 2
The library syntax is polred(GEN T)
(flag = 0). Also available is
GEN polred2(GEN T)
(flag = 2). The function polred0
is
deprecated, provided for backward compatibility.
Returns a canonical defining polynomial P for the number field
ℚ[X]/(T) defined by T, such that the sum of the squares of the modulus
of the roots (i.e. the T2-norm) is minimal. Different T defining
isomorphic number fields will yield the same P. All T accepted by
nfinit
are also allowed here, e.g. nonmonic polynomials, or pairs
[T, listP]
specifying that a nonmaximal order may be used. For
convenience, any number field structure (nf, bnf,...) can also
be used instead of T.
? polredabs(x^2 + 16) %1 = x^2 + 1 ? K = bnfinit(x^2 + 16); polredabs(K) %2 = x^2 + 1
Warning 1. Using a t_POL
T requires computing
and fully factoring the discriminant dK of the maximal order which may be
very hard. You can use the format [T, listP]
, where listP
encodes a list of known coprime divisors of disc(T) (see ??nfbasis
),
to help the routine, thereby replacing this part of the algorithm by a
polynomial time computation But this may only compute a suborder of the
maximal order, when the divisors are not squarefree or do not include all
primes dividing dK. The routine attempts to certify the result
independently of this order computation as per nfcertify
: we try to
prove that the computed order is maximal. If the certification fails,
the routine then fully factors the integers returned by nfcertify
.
You can also use polredbest
to avoid this factorization step; in this
case, the result is small but no longer canonical.
Warning 2. Apart from the factorization of the discriminant of
T, this routine runs in polynomial time for a fixed degree.
But the complexity is exponential in the degree: this routine
may be exceedingly slow when the number field has many subfields, hence a
lot of elements of small T2-norm. If you do not need a canonical
polynomial, the function polredbest
is in general much faster (it runs
in polynomial time), and tends to return polynomials with smaller
discriminants.
The binary digits of flag mean
1: outputs a two-component row vector [P,a], where P is the default
output and Mod(a, P)
is a root of the original T.
4: gives all polynomials of minimal T2 norm; of the two polynomials P(x) and ± P(-x), only one is given.
16: (OBSOLETE) Possibly use a suborder of the maximal order, without
attempting to certify the result as in Warning 1. This makes polredabs
behave like polredbest
. Just use the latter.
? T = x^16 - 136*x^14 + 6476*x^12 - 141912*x^10 + 1513334*x^8 \ - 7453176*x^6 + 13950764*x^4 - 5596840*x^2 + 46225 ? T1 = polredabs(T); T2 = polredbest(T); ? [ norml2(polroots(T1)), norml2(polroots(T2)) ] %3 = [88.0000000, 120.000000] ? [ sizedigit(poldisc(T1)), sizedigit(poldisc(T2)) ] %4 = [75, 67]
The precise definition of the output of polredabs
is as follows.
* Consider the finite list of characteristic polynomials of primitive elements of K that are in ℤK and minimal for the T2 norm; now remove from the list the polynomials whose discriminant do not have minimal absolute value. Note that this condition is restricted to the original list of polynomials with minimal T2 norm and does not imply that the defining polynomial for the field with smallest discriminant belongs to the list !
* To a polynomial P(x) = xn +...+ an ∈ ℝ[x] we attach
the sequence S(P) given by |a1|, a1,..., |an|, an.
Order the polynomials P by the lexicographic order on the coefficient
vectors S(P). Then the output of polredabs
is the smallest
polynomial in the above list for that order. In other words, the monic
polynomial which is lexicographically smallest with respect to the absolute
values of coefficients, favouring negative coefficients to break ties, i.e.
choosing x3-2 rather than x3+2.
The library syntax is GEN polredabs0(GEN T, long flag)
.
Instead of the above hardcoded numerical flags, one should use an
or-ed combination of
* nf_PARTIALFACT
(OBSOLETE): possibly use a suborder of the maximal
order, without attempting to certify the result.
* nf_ORIG
: return [P, a], where Mod(a, P)
is a root of T.
* nf_RAW
: return [P, b], where Mod(b, T)
is a root of P.
The algebraic integer b is the raw result produced by the small vectors
enumeration in the maximal order; P was computed as the characteristic
polynomial of Mod(b, T)
. Mod(a, P)
as in nf_ORIG
is obtained with modreverse
.
* nf_ADDZK
: if r is the result produced with some of the above
flags (of the form P or [P,c]), return [r,zk]
, where zk
is a
ℤ-basis for the maximal order of ℚ[X]/(P).
* nf_ALL
: return a vector of results of the above form, for all
polynomials of minimal T2-norm.
Finds a polynomial with reasonably
small coefficients defining the same number field as T.
All T accepted by nfinit
are also allowed here (e.g. nonmonic
polynomials, nf
, bnf
, [T,Z_K_basis]
). Contrary to
polredabs
, this routine runs in polynomial time, but it offers no
guarantee as to the minimality of its result.
This routine computes an LLL-reduced basis for an order in ℚ[X]/(T), then
examines small linear combinations of the basis vectors, computing their
characteristic polynomials. It returns the separable polynomial P of
smallest discriminant, the one with lexicographically smallest
abs(Vec(P))
in case of ties. This is a good candidate for subsequent
number field computations since it guarantees that the denominators of
algebraic integers, when expressed in the power basis, are reasonably small.
With no claim of minimality, though.
It can happen that iterating this functions yields better and better polynomials, until it stabilizes:
? \p5 ? P = X^12+8*X^8-50*X^6+16*X^4-3069*X^2+625; ? poldisc(P)*1. %2 = 1.2622 E55 ? P = polredbest(P); ? poldisc(P)*1. %4 = 2.9012 E51 ? P = polredbest(P); ? poldisc(P)*1. %6 = 8.8704 E44
In this example, the initial polynomial P is the one
returned by polredabs
, and the last one is stable.
If flag = 1: outputs a two-component row vector [P,a], where P is the
default output and a
, a t_POLMOD
modulo P
, is a root of the
original T.
? [P,a] = polredbest(x^4 + 8, 1) %1 = [x^4 + 2, Mod(x^3, x^4 + 2)] ? charpoly(a) %2 = x^4 + 8
In particular, the map ℚ[x]/(T) → ℚ[x]/(P),
x ⟼
a
defines an isomorphism of number fields, which can
be computed as
subst(lift(Q), 'x, a)
if Q is a t_POLMOD
modulo T; b = modreverse(a)
returns a t_POLMOD
giving the inverse of the above map (which should be
useless since ℚ[x]/(P) is a priori a better representation for the number
field and its elements).
The library syntax is GEN polredbest(GEN T, long flag)
.
This function is obsolete, use polredbest.
The library syntax is GEN polredord(GEN x)
.
Applies a random Tschirnhausen
transformation to the polynomial x, which is assumed to be nonconstant
and separable, so as to obtain a new equation for the étale algebra
defined by x. This is for instance useful when computing resolvents,
hence is used by the polgalois
function.
The library syntax is GEN tschirnhaus(GEN x)
.
Expresses x on the relative
integral basis. Here, rnf is a relative number field extension L/K
as output by rnfinit
, and x an element of L in absolute form, i.e.
expressed as a polynomial or polmod with polmod coefficients, not on
the relative integral basis.
The library syntax is GEN rnfalgtobasis(GEN rnf, GEN x)
.
Let K the field represented by
bnf, as output by bnfinit
. M is a projective ℤK-module
of rank n (M ⨂ K is an n-dimensional K-vector space), given by a
pseudo-basis of size n. The routine returns either a true ℤK-basis of
M (of size n) if it exists, or an n+1-element generating set of M if
not.
It is allowed to use a monic irreducible polynomial P in K[X] instead of M, in which case, M is defined as the ring of integers of K[X]/(P), viewed as a ℤK-module.
Huge discriminants, helping rnfdisc. The format [T,B] is
also accepted instead of T and computes an order which is maximal at all
maximal ideals specified by B, see ??rnfinit
: the valuation of D is
then correct at all such maximal ideals but may be incorrect at other primes.
The library syntax is GEN rnfbasis(GEN bnf, GEN M)
.
Computes the representation of x
as a polmod with polmods coefficients. Here, rnf is a relative number
field extension L/K as output by rnfinit
, and x an element of
L expressed on the relative integral basis.
The library syntax is GEN rnfbasistoalg(GEN rnf, GEN x)
.
Characteristic polynomial of a over nf, where a belongs to the algebra defined by T over nf, i.e. nf[X]/(T). Returns a polynomial in variable v (x by default).
? nf = nfinit(y^2+1); ? rnfcharpoly(nf, x^2+y*x+1, x+y) %2 = x^2 + Mod(-y, y^2 + 1)*x + 1
The library syntax is GEN rnfcharpoly(GEN nf, GEN T, GEN a, long var = -1)
where var
is a variable number.
Given a bnf structure attached to a number field K, as produced
by bnfinit
, and T an irreducible polynomial in K[x]
defining an Abelian extension L = K[x]/(T), computes the class field
theory conductor of this Abelian extension. If T does not define an Abelian
extension over K, the result is undefined; it may be the integer 0 (in
which case the extension is definitely not Abelian) or a wrong result.
The result is a 3-component vector [f,bnr,H], where f is the
conductor of the extension given as a 2-component row vector
[f0,f oo ],
bnr is the attached bnr
structure and H is a matrix in HNF
defining the subgroup of the ray class group on the ray class group generators
bnr.gen
; in particular, it is a left divisor of the diagonal matrix
attached to bnr.cyc
and |det H |= N = deg T.
* If flag is 1, return [f,bnrmod, H], where
bnrmod
is now attached to Clf / ClfN,
and H is as
before since it contains the N-th powers. This is useful when f contains
a maximal ideal with huge residue field, since the corresponding tough
discrete logarithms are trivialized: in the quotient group, all elements have
small order dividing N. This allows to work in Clf/H but no
longer in Clf.
* If flag is 2, only return [f, fa
] where fa
is the
factorization of the conductor finite part ( = f[1]).
Huge discriminants, helping rnfdisc. The format [T,B] is
also accepted instead of T and computes the conductor of the extension
provided it factors completely over the maximal ideals specified by B,
see ??rnfinit
: the valuation of f0 is then correct at all such
maximal ideals but may be incorrect at other primes.
The library syntax is GEN rnfconductor0(GEN bnf, GEN T, long flag)
.
Also available is GEN rnfconductor(GEN bnf, GEN T)
when flag =
0.
Given a number field K coded by nf and a monic polynomial P ∈ ℤK[X], irreducible over K and thus defining a relative extension L of K, applies Dedekind's criterion to the order ℤK[X]/(P), at the prime ideal pr. It is possible to set pr to a vector of prime ideals (test maximality at all primes in the vector), or to omit altogether, in which case maximality at all primes is tested; in this situation flag is automatically set to 1.
The default historic behavior (flag is 0 or omitted and pr is a
single prime ideal) is not so useful since
rnfpseudobasis
gives more information and is generally not that
much slower. It returns a 3-component vector [max, basis, v]:
* basis is a pseudo-basis of an enlarged order O produced by Dedekind's criterion, containing the original order ℤK[X]/(P) with index a power of pr. Possibly equal to the original order.
* max is a flag equal to 1 if the enlarged order O could be proven to be pr-maximal and to 0 otherwise; it may still be maximal in the latter case if pr is ramified in L,
* v is the valuation at pr of the order discriminant.
If flag is nonzero, on the other hand, we just return 1 if the order ℤK[X]/(P) is pr-maximal (resp. maximal at all relevant primes, as described above), and 0 if not. This is much faster than the default, since the enlarged order is not computed.
? nf = nfinit(y^2-3); P = x^3 - 2*y; ? pr3 = idealprimedec(nf,3)[1]; ? rnfdedekind(nf, P, pr3) %3 = [1, [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, 1]], 8] ? rnfdedekind(nf, P, pr3, 1) %4 = 1
In this example, pr3
is the ramified ideal above 3,
and the order generated by the cube roots of y is already
pr3
-maximal. The order-discriminant has valuation 8. On the other
hand, the order is not maximal at the prime above 2:
? pr2 = idealprimedec(nf,2)[1]; ? rnfdedekind(nf, P, pr2, 1) %6 = 0 ? rnfdedekind(nf, P, pr2) %7 = [0, [[2, 0, 0; 0, 1, 0; 0, 0, 1], [[1, 0; 0, 1], [1, 0; 0, 1], [1, 1/2; 0, 1/2]]], 2]
The enlarged order is not proven to be pr2
-maximal yet. In fact, it
is; it is in fact the maximal order:
? B = rnfpseudobasis(nf, P) %8 = [[1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 1, [1, 1/2; 0, 1/2]], [162, 0; 0, 162], -1] ? idealval(nf,B[3], pr2) %9 = 2
It is possible to use this routine with nonmonic
P = ∑i ≤ n pi Xi ∈ ℤK[X] if flag = 1;
in this case, we test maximality of Dedekind's order generated by
1, pn α, pnα2 + pn-1α,...,
pnαn-1 + pn-1αn-2 +...+ p1α.
The routine will fail if P vanishes on the projective line over the residue
field ℤK/pr
(FIXME).
The library syntax is GEN rnfdedekind(GEN nf, GEN pol, GEN pr = NULL, long flag)
.
Given a pseudo-matrix M over the maximal order of nf, computes its determinant.
The library syntax is GEN rnfdet(GEN nf, GEN M)
.
Given an nf structure attached to a number field K, as output
by nfinit
, and a monic irreducible polynomial T ∈ K[x] defining a
relative extension L = K[x]/(T), compute the relative discriminant of L.
This is a vector [D,d], where D is the relative ideal discriminant and
d is the relative discriminant considered as an element of
K*/{K*}2.
The main variable of nf must be of lower priority than that of
T, see Section se:priority.
Huge discriminants, helping rnfdisc. The format [T,B] is
also accepted instead of T and computes an order which is maximal at all
maximal ideals specified by B, see ??rnfinit
: the valuation of D is
then correct at all such maximal ideals but may be incorrect at other primes.
The library syntax is GEN rnfdiscf(GEN nf, GEN T)
.
Let rnf be a relative number field extension L/K as output by
rnfinit
and let x be an
element of L expressed either
* as a polynomial modulo the absolute equation rnf.polabs
,
* or in terms of the absolute ℤ-basis for ℤL if rnf
contains one (as in rnfinit(nf,pol,1)
, or after a call to
nfinit(rnf)
).
Computes x as an element of the relative extension L/K as a polmod with polmod coefficients. If x is actually rational, return it as a rational number:
? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.polabs %2 = x^4 + 1 ? rnfeltabstorel(L, Mod(x, L.polabs)) %3 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, 1/3) %4 = 1/3 ? rnfeltabstorel(L, Mod(x, x^2-y)) %5 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, [0,0,0,1]~) \\ ZL not initialized yet *** at top-level: rnfeltabstorel(L,[0, *** ^ — — — — — — -- *** rnfeltabstorel: incorrect type in rnfeltabstorel, apply nfinit(rnf). ? nfinit(L); \\ initialize now ? rnfeltabstorel(L, [0,0,0,1]~) %6 = Mod(Mod(y, y^2 + 1)*x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltabstorel(L, [1,0,0,0]~) %7 = 1
The library syntax is GEN rnfeltabstorel(GEN rnf, GEN x)
.
rnf being a relative number
field extension L/K as output by rnfinit
and x being an element of
L expressed as a polynomial or polmod with polmod coefficients (or as a
t_COL
on nfinit(rnf).zk
), computes
x as an element of K as a t_POLMOD
if flag = 0 and as a t_COL
otherwise. If x is not in K, a domain error occurs. Note that if x
is in fact rational, it is returned as a rational number, ignoring flag.
? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltdown(L, Mod(x^2, L.pol)) %3 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(x^2, L.pol), 1) %4 = [0, 1]~ ? rnfeltdown(L, Mod(y, x^2-y)) %5 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(y,K.pol)) %6 = Mod(y, y^2 + 1) ? rnfeltdown(L, Mod(x, L.pol)) *** at top-level: rnfeltdown(L,Mod(x,x *** ^ — — — — — — -- *** rnfeltdown: domain error in rnfeltdown: element not in the base field ? rnfeltdown(L, Mod(y, x^2-y), 1) \\ as a t_COL %7 = [0, 1]~ ? rnfeltdown(L, [0,0,1,0]~) \\ not allowed without absolute nf struct *** rnfeltdown: incorrect type in rnfeltdown (t_COL). ? nfinit(L); \\ add absolute nf structure to L ? rnfeltdown(L, [0,0,1,0]~) \\ now OK %8 = Mod(y, y^2 + 1)
If we had started with
L = rnfinit(K, x^2-y, 1)
, then the final command would have worked
directly.
The library syntax is GEN rnfeltdown0(GEN rnf, GEN x, long flag)
.
Also available is
GEN rnfeltdown(GEN rnf, GEN x)
(flag = 0).
rnf being a relative number field extension L/K as output by
rnfinit
and x being an element of L, returns the relative norm
NL/K(x) as an element of K.
? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? rnfeltnorm(L, Mod(x, L.pol)) %2 = Mod(x, x^2 + Mod(-y, y^2 + 1)) ? rnfeltnorm(L, 2) %3 = 4
The library syntax is GEN rnfeltnorm(GEN rnf, GEN x)
.
rnf being a relative
number field extension L/K as output by rnfinit
and x being an
element of L expressed as a polynomial or polmod with polmod
coefficients, computes x as an element of the absolute extension L/ℚ as
a polynomial modulo the absolute equation rnf.polabs
.
? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.polabs %2 = x^4 + 1 ? rnfeltreltoabs(L, Mod(x, L.pol)) %3 = Mod(x, x^4 + 1) ? rnfeltreltoabs(L, Mod(y, x^2-y)) %4 = Mod(x^2, x^4 + 1) ? rnfeltreltoabs(L, Mod(y,K.pol)) %5 = Mod(x^2, x^4 + 1)
If the input is actually rational, then rnfeltreltoabs
returns it as a rational number instead of a t_POLMOD
:
? rnfeltreltoabs(L, Mod(2, K.pol)) %6 = 2
The library syntax is GEN rnfeltreltoabs(GEN rnf, GEN x)
.
rnf being a relative number field extension L/K as output by
rnfinit
and x being an element of L, returns the relative trace
TrL/K(x) as an element of K.
? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? rnfelttrace(L, Mod(x, L.pol)) %2 = 0 ? rnfelttrace(L, 2) %3 = 4
The library syntax is GEN rnfelttrace(GEN rnf, GEN x)
.
rnf being a relative number field extension L/K as output by
rnfinit
and x being an element of K, computes x as an element of
the absolute extension L/ℚ. As a t_POLMOD
modulo rnf.pol
if flag = 0 and as a t_COL
on the absolute field integer basis if
flag = 1. Note that if x
is in fact rational, it is returned as a rational number, ignoring flag.
? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); ? L.pol %2 = x^4 + 1 ? rnfeltup(L, Mod(y, K.pol)) %3 = Mod(x^2, x^4 + 1) ? rnfeltup(L, y) %4 = Mod(x^2, x^4 + 1) ? rnfeltup(L, [1,2]~) \\ in terms of K.zk %5 = Mod(2*x^2 + 1, x^4 + 1) ? rnfeltup(L, y, 1) \\ in terms of nfinit(L).zk %6 = [0, 1, 0, 0]~ ? rnfeltup(L, [1,2]~, 1) %7 = [1, 2, 0, 0]~ ? rnfeltup(L, [1,0]~) \\ rational %8 = 1
The library syntax is GEN rnfeltup0(GEN rnf, GEN x, long flag)
.
Also available is
GEN rnfeltup(GEN rnf, GEN x)
(flag = 0).
Given a number field nf as output by nfinit
(or simply a monic irreducible integral polynomial defining the field)
and a polynomial pol with coefficients in nf defining a
relative extension L of nf, computes an absolute equation of L
over ℚ.
The main variable of nf must be of lower priority than that
of pol (see Section se:priority). Note that for efficiency, this does
not check whether the relative equation is irreducible over nf, but
only if it is squarefree. If it is reducible but squarefree, the result will
be the absolute equation of the étale algebra defined by pol. If
pol is not squarefree, raise an e_DOMAIN
exception.
? rnfequation(y^2+1, x^2 - y) %1 = x^4 + 1 ? T = y^3-2; rnfequation(nfinit(T), (x^3-2)/(x-Mod(y,T))) %2 = x^6 + 108 \\ Galois closure of Q(2^(1/3))
If flag is nonzero, outputs a 3-component row vector [z,a,k], where
* z is the absolute equation of L over ℚ, as in the default behavior,
* a expresses as a t_POLMOD
modulo z a root α of the
polynomial defining the base field nf,
* k is a small integer such that θ = β+kα is a root of z, where β is a root of pol. It is guaranteed that k = 0 whenever ℚ(β) = L.
? T = y^3-2; pol = x^2 +x*y + y^2; ? [z,a,k] = rnfequation(T, pol, 1); ? z %3 = x^6 + 108 ? subst(T, y, a) %4 = 0 ? alpha= Mod(y, T); ? beta = Mod(x*Mod(1,T), pol); ? subst(z, x, beta + k*alpha) %7 = 0
The library syntax is GEN rnfequation0(GEN nf, GEN pol, long flag)
.
Also available are
GEN rnfequation(GEN nf, GEN pol)
(flag = 0) and
GEN rnfequation2(GEN nf, GEN pol)
(flag = 1).
Given a bnf attached to a number field K and a projective
ℤK-module M given by a pseudo-matrix, returns either a true HNF basis
of M if one exists, or zero otherwise. If M is a polynomial with
coefficients in K, replace it by the pseudo-matrix returned by
rnfpseudobasis
.
The library syntax is GEN rnfhnfbasis(GEN bnf, GEN M)
.
Let rnf be a relative
number field extension L/K as output by rnfinit
and let x be an
ideal of the absolute extension L/ℚ. Returns the relative pseudo-matrix in
HNF giving the ideal x considered as an ideal of the relative extension
L/K, i.e. as a ℤK-module.
Let Labs
be an (absolute) nf
structure attached to L,
obtained via Labs = nfinit(rnf))
. Then rnf
"knows" about
Labs
and x may be given in any format
attached to Labs
, e.g. a prime ideal or an ideal in HNF wrt.
Labs.zk
:
? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); Labs = nfinit(rnf); ? m = idealhnf(Labs, 17, x^3+2); \\ some ideal in HNF wrt. Labs.zk ? B = rnfidealabstorel(rnf, m) %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] \\ pseudo-basis for m as ZK-module ? A = rnfidealreltoabs(rnf, B) %4 = [17, x^2 + 4, x + 8, x^3 + 8*x^2] \\ Z-basis for m in Q[x]/(rnf.polabs) ? mathnf(matalgtobasis(Labs, A)) == m %5 = 1
If on the other hand, we do not have a Labs
at hand,
because it would be too expensive to compute, but we nevertheless have
a ℤ-basis for x, then we can use the function with this basis as
argument. The entries of x may be given either modulo rnf.polabs
(absolute form, possibly lifted) or modulo rnf.pol
(relative form as
t_POLMOD
s):
? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? rnfidealabstorel(rnf, [17, x^2 + 4, x + 8, x^3 + 8*x^2]) %2 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]] ? rnfidealabstorel(rnf, Mod([17, y + 4, x + 8, y*x + 8*y], x^2-y)) %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]]
The library syntax is GEN rnfidealabstorel(GEN rnf, GEN x)
.
Let rnf be a relative number
field extension L/K as output by rnfinit
, and x an ideal of
L, given either in relative form or by a ℤ-basis of elements of L
(see Section se:rnfidealabstorel). This function returns the ideal of K
below x, i.e. the intersection of x with K.
The library syntax is GEN rnfidealdown(GEN rnf, GEN x)
.
Factor into prime ideal powers the
ideal x in the attached absolute number field L = nfinit
(rnf).
The output format is similar to the factor
function, and the prime
ideals are represented in the form output by the idealprimedec
function for L.
? rnf = rnfinit(nfinit(y^2+1), x^2-y+1); ? rnfidealfactor(rnf, y+1) \\ P2^2 %2 = [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 2] ? rnfidealfactor(rnf, x) \\ P2 %3 = [[2, [0,0,1,0]~, 4, 1, [0,0,0,2;0,0,-2,0;-1,-1,0,0;1,-1,0,0]] 1] ? L = nfinit(rnf); ? id = idealhnf(L, idealhnf(L, 25, (x+1)^2)); ? idealfactor(L, id) == rnfidealfactor(rnf, id) %6 = 1
Note that ideals of the base field K must be explicitly
lifted to L via rnfidealup
before they can be factored.
The library syntax is GEN rnfidealfactor(GEN rnf, GEN x)
.
rnf being a relative number
field extension L/K as output by rnfinit
and x being a relative
ideal (which can be, as in the absolute case, of many different types,
including of course elements), computes the HNF pseudo-matrix attached to
x, viewed as a ℤK-module.
The library syntax is GEN rnfidealhnf(GEN rnf, GEN x)
.
rnf being a relative number
field extension L/K as output by rnfinit
and x and y being ideals
of the relative extension L/K given by pseudo-matrices, outputs the ideal
product, again as a relative ideal.
The library syntax is GEN rnfidealmul(GEN rnf, GEN x, GEN y)
.
Let rnf be a relative
number field extension L/K as output by rnfinit
and let x be a
relative ideal (which can be, as in the absolute case, of many different
types, including of course elements). This function computes the norm of the
x considered as an ideal of the absolute extension L/ℚ. This is
identical to
idealnorm(rnf, rnfidealnormrel(rnf,x))
but faster.
The library syntax is GEN rnfidealnormabs(GEN rnf, GEN x)
.
Let rnf be a relative
number field extension L/K as output by rnfinit
and let x be a
relative ideal (which can be, as in the absolute case, of many different
types, including of course elements). This function computes the relative
norm of x as an ideal of K in HNF.
The library syntax is GEN rnfidealnormrel(GEN rnf, GEN x)
.
Let rnf be a relative number
field extension L/K as output by rnfinit
, and pr a maximal
ideal of K (prid), this function completes the rnf
with a nf structure attached to L (see Section se:rnfinit)
and returns the vector S of prime ideals of ℤL above pr.
? K = nfinit(y^2+1); rnf = rnfinit(K, x^3+y+1); ? pr = idealprimedec(K, 2)[1]; ? S = rnfidealprimedec(rnf, pr); ? #S %4 = 1
The relative ramification indices and residue degrees
can be obtained as PR.e / pr.e
and PR.f / PR.f
, if PR
is an element of S.
The argument pr is also allowed to be a prime number p, in which
case the function returns a pair of vectors [SK,SL]
, where SK
contains the primes of K above p and SL
[i] is the vector of primes
of L above SK
[i].
? [SK,SL] = rnfidealprimedec(rnf, 5); ? [#SK, vector(#SL,i,#SL[i])] %6 = [2, [2, 2]]
The library syntax is GEN rnfidealprimedec(GEN rnf, GEN pr)
.
Let rnf be a relative
number field extension L/K as output by rnfinit
and let x be a
relative ideal, given as a ℤK-module by a pseudo matrix [A,I].
This function returns the ideal x as an absolute ideal of L/ℚ.
If flag = 0, the result is given by a vector of t_POLMOD
s modulo
rnf.pol
forming a ℤ-basis; if flag = 1, it is given in HNF in terms
of the fixed ℤ-basis for ℤL, see Section se:rnfinit.
? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? P = idealprimedec(K,2)[1]; ? P = rnfidealup(rnf, P) %3 = [2, x^2 + 1, 2*x, x^3 + x] ? Prel = rnfidealhnf(rnf, P) %4 = [[1, 0; 0, 1], [[2, 1; 0, 1], [2, 1; 0, 1]]] ? rnfidealreltoabs(rnf,Prel) %5 = [2, x^2 + 1, 2*x, x^3 + x] ? rnfidealreltoabs(rnf,Prel,1) %6 = [2 1 0 0] [0 1 0 0] [0 0 2 1] [0 0 0 1]
The reason why we do not return by default (flag = 0) the customary HNF in terms of a fixed ℤ-basis for ℤL is precisely because a rnf does not contain such a basis by default. Completing the structure so that it contains a nf structure for L is polynomial time but costly when the absolute degree is large, thus it is not done by default. Note that setting flag = 1 will complete the rnf.
The library syntax is GEN rnfidealreltoabs0(GEN rnf, GEN x, long flag)
.
Also available is
GEN rnfidealreltoabs(GEN rnf, GEN x)
(flag = 0).
rnf being a relative
number field extension L/K as output by rnfinit
and x being an
ideal of the relative extension L/K given by a pseudo-matrix, gives a
vector of two generators of x over ℤL expressed as polmods with polmod
coefficients.
The library syntax is GEN rnfidealtwoelement(GEN rnf, GEN x)
.
Let rnf be a relative number
field extension L/K as output by rnfinit
and let x be an ideal of
K. This function returns the ideal xℤL as an absolute ideal of L/ℚ,
in the form of a ℤ-basis. If flag = 0, the result is given by a vector of
polynomials (modulo rnf.pol
); if flag = 1, it is given in HNF in terms
of the fixed ℤ-basis for ℤL, see Section se:rnfinit.
? K = nfinit(y^2+1); rnf = rnfinit(K, x^2-y); ? P = idealprimedec(K,2)[1]; ? rnfidealup(rnf, P) %3 = [2, x^2 + 1, 2*x, x^3 + x] ? rnfidealup(rnf, P,1) %4 = [2 1 0 0] [0 1 0 0] [0 0 2 1] [0 0 0 1]
The reason why we do not return by default (flag = 0) the customary HNF in terms of a fixed ℤ-basis for ℤL is precisely because a rnf does not contain such a basis by default. Completing the structure so that it contains a nf structure for L is polynomial time but costly when the absolute degree is large, thus it is not done by default. Note that setting flag = 1 will complete the rnf.
The library syntax is GEN rnfidealup0(GEN rnf, GEN x, long flag)
.
Also available is
GEN rnfidealup(GEN rnf, GEN x)
(flag = 0).
Given an nf structure attached to a number field K, as output by
nfinit
, and a monic irreducible polynomial T in ℤK[x] defining a
relative extension L = K[x]/(T), this computes data to work in L/K
The main variable of T must be of higher priority
(see Section se:priority) than that of nf, and the coefficients of
T must be in K.
The result is a row vector, whose components are technical. We let m = [K:ℚ] the degree of the base field, n = [L:K] the relative degree, r1 and r2 the number of real and complex places of K. Access to this information via member functions is preferred since the specific data organization specified below will change in the future.
If flag = 1, add an nf structure attached to L to rnf.
This is likely to be very expensive if the absolute degree mn is large,
but fixes an integer basis for ℤL as a ℤ-module and allows to input
and output elements of L in absolute form: as t_COL
for elements,
as t_MAT
in HNF for ideals, as prid
for prime ideals. Without such
a call, elements of L are represented as t_POLMOD
, etc.
Note that a subsequent nfinit
(rnf) will also explicitly
add such a component, and so will the following functions rnfidealmul
,
rnfidealtwoelt
, rnfidealprimedec
, rnfidealup
(with flag 1)
and rnfidealreltoabs
(with flag 1). The absolute nf structure
attached to L can be recovered using nfinit(rnf)
.
rnf[1](rnf.pol
) contains the relative polynomial T.
rnf[2] contains the integer basis [A,d] of K, as (integral) elements of L/ℚ. More precisely, A is a vector of polynomial with integer coefficients, d is a denominator, and the integer basis is given by A/d.
rnf[3] (rnf.disc
) is a two-component row vector
[𝔡(L/K),s] where 𝔡(L/K) is the relative ideal discriminant
of L/K and s is the discriminant of L/K viewed as an element of
K*/(K*)2, in other words it is the output of rnfdisc
.
rnf[4](rnf.index
) is the ideal index 𝔣, i.e. such
that d(T)ℤK = 𝔣2𝔡(L/K).
rnf[5](rnf.p
) is the list of rational primes dividing the norm
of the relative discriminant ideal.
rnf[7] (rnf.zk
) is the pseudo-basis (A,I) for the maximal
order ℤL as a ℤK-module: A is the relative integral pseudo basis
expressed as polynomials (in the variable of T) with polmod coefficients
in nf, and the second component I is the ideal list of the
pseudobasis in HNF.
rnf[8] is the inverse matrix of the integral basis matrix, with coefficients polmods in nf.
rnf[9] is currently unused.
rnf[10] (rnf.nf
) is nf.
rnf[11] is an extension of rnfequation(K, T, 1)
. Namely, a
vector [P, a, k, K.pol
, T] describing the absolute
extension L/ℚ: P is an absolute equation, more conveniently obtained
as rnf.polabs
; a expresses the generator α = y mod K.pol
of the number field K as an element of L, i.e. a polynomial modulo the
absolute equation P;
k is a small integer such that, if β is an abstract root of T and α the generator of K given above, then P(β + kα) = 0. It is guaranteed that k = 0 if ℚ(β) = L.
Caveat. Be careful if k ! = 0 when dealing simultaneously with absolute and relative quantities since L = ℚ(β + kα) = K(α), and the generator chosen for the absolute extension is not the same as for the relative one. If this happens, one can of course go on working, but we advise to change the relative polynomial so that its root becomes β + k α. Typical GP instructions would be
[P,a,k] = rnfequation(K, T, 1); if (k, T = subst(T, x, x - k*Mod(y, K.pol))); L = rnfinit(K, T);
rnf[12] is by default unused and set equal to 0. This field is used
to store further information about the field as it becomes available (which
is rarely needed, hence would be too expensive to compute during the initial
rnfinit
call).
Huge discriminants, helping rnfdisc. When T has a
discriminant which is difficult to factor, it is hard to compute
ℤL. As in nfinit
, the special input format [T,B]
is also accepted, where T is a polynomial as above and B specifies a
list of maximal ideals. The following formats are recognized for B:
* an integer: the list of all maximal ideals above a rational prime p < B.
* a vector of rational primes or prime ideals: the list of all maximal ideals dividing an element in the list.
Instead of ℤL, this produces an order which is maximal at all such maximal ideals primes. The result may actually be a complete and correct rnf structure if the relative ideal discriminant factors completely over this list of maximal ideals but this is not guaranteed. In general, the order may not be maximal at primes 𝔭 not in the list such that 𝔭2 divides the relative ideal discriminant.
The library syntax is GEN rnfinit0(GEN nf, GEN T, long flag)
.
Also available is
GEN rnfinit(GEN nf,GEN T)
(flag = 0).
T being a relative polynomial with coefficients in nf, return 1 if it defines an abelian extension, and 0 otherwise.
? K = nfinit(y^2 + 23); ? rnfisabelian(K, x^3 - 3*x - y) %2 = 1
The library syntax is long rnfisabelian(GEN nf, GEN T)
.
Given a bnf attached to a number field K and
a projective ℤK-module M given by a pseudo-matrix, return true (1) if
M is free else return false (0). If M is a polynomial with coefficients
in K, replace it by the pseudo-matrix returned by rnfpseudobasis
.
The library syntax is long rnfisfree(GEN bnf, GEN M)
.
Let rnf be a relative number field extension L/K as output
by rnfinit
whose degree [L:K] is a power of a prime ℓ.
Return 1 if the ℓ-extension is locally cyclotomic (locally contained in
the cyclotomic ℤℓ-extension of Kv at all places v | ℓ), and
0 if not.
? K = nfinit(y^2 + y + 1); ? L = rnfinit(K, x^3 - y); /* = K(zeta9), globally cyclotomic */ ? rnfislocalcyclo(L) %3 = 1 \\ we expect 3-adic continuity by Krasner's lemma ? vector(5, i, rnfislocalcyclo(rnfinit(K, x^3 - y + 3^i))) %5 = [0, 1, 1, 1, 1]
The library syntax is long rnfislocalcyclo(GEN rnf)
.
Similar to
bnfisnorm
but in the relative case. T is as output by
rnfisnorminit
applied to the extension L/K. This tries to decide
whether the element a in K is the norm of some x in the extension
L/K.
The output is a vector [x,q], where a = Norm(x)*q. The algorithm looks for a solution x which is an S-integer, with S a list of places of K containing at least the ramified primes, the generators of the class group of L, as well as those primes dividing a. If L/K is Galois, then this is enough but you may want to add more primes to S to produce different elements, possibly smaller; otherwise, flag is used to add more primes to S: all the places above the primes p ≤ flag (resp. p|flag) if flag > 0 (resp. flag < 0).
The answer is guaranteed (i.e. a is a norm iff q = 1) if the field is Galois, or, under GRH, if S contains all primes less than 4log2|disc(M)|, where M is the normal closure of L/K.
If rnfisnorminit
has determined (or was told) that L/K is
Galois, and flag ! = 0, a Warning is issued (so that you can set
flag = 1 to check whether L/K is known to be Galois, according to T).
Example:
bnf = bnfinit(y^3 + y^2 - 2*y - 1); p = x^2 + Mod(y^2 + 2*y + 1, bnf.pol); T = rnfisnorminit(bnf, p); rnfisnorm(T, 17)
checks whether 17 is a norm in the Galois extension ℚ(β) / ℚ(α), where α3 + α2 - 2α - 1 = 0 and β2 + α2 + 2α + 1 = 0 (it is).
The library syntax is GEN rnfisnorm(GEN T, GEN a, long flag)
.
Let K be defined by a root of pol, and L/K the extension defined
by the polynomial polrel. As usual, pol can in fact be an nf,
or bnf, etc; if pol has degree 1 (the base field is ℚ),
polrel is also allowed to be an nf, etc. Computes technical data needed
by rnfisnorm
to solve norm equations Nx = a, for x in L, and a
in K.
If flag = 0, do not care whether L/K is Galois or not.
If flag = 1, L/K is assumed to be Galois (unchecked), which speeds up
rnfisnorm
.
If flag = 2, let the routine determine whether L/K is Galois.
The library syntax is GEN rnfisnorminit(GEN pol, GEN polrel, long flag)
.
This function is deprecated, use bnrclassfield
.
The library syntax is GEN rnfkummer(GEN bnr, GEN subgp = NULL, long prec)
.
Given a polynomial
pol with coefficients in nf defining a relative extension L and
a suborder order of L (of maximal rank), as output by
rnfpseudobasis
(nf,pol) or similar, gives
[[neworder],U], where neworder is a reduced order and U is
the unimodular transformation matrix.
The library syntax is GEN rnflllgram(GEN nf, GEN pol, GEN order, long prec)
.
bnr being a big ray
class field as output by bnrinit
and pol a relative polynomial
defining an Abelian extension, computes the norm group (alias Artin
or Takagi group) corresponding to the Abelian extension of
bnf = bnr.bnf
defined by pol, where the module corresponding to bnr is assumed
to be a multiple of the conductor (i.e. pol defines a subextension of
bnr). The result is the HNF defining the norm group on the given generators
of bnr.gen
. Note that neither the fact that pol defines an
Abelian extension nor the fact that the module is a multiple of the conductor
is checked. The result is undefined if the assumption is not correct,
but the function will return the empty matrix [;]
if it detects a
problem; it may also not detect the problem and return a wrong result.
The library syntax is GEN rnfnormgroup(GEN bnr, GEN pol)
.
This function is obsolete: use rnfpolredbest
instead.
Relative version of polred
. Given a monic polynomial pol with
coefficients in nf, finds a list of relative polynomials defining some
subfields, hopefully simpler and containing the original field. In the present
version 2.17.0, this is slower and less efficient than rnfpolredbest
.
Remark. This function is based on an incomplete reduction
theory of lattices over number fields, implemented by rnflllgram
, which
deserves to be improved.
The library syntax is GEN rnfpolred(GEN nf, GEN pol, long prec)
.
Relative version of polredabs
. Given an irreducible monic polynomial
pol with coefficients in the maximal order of nf, finds a
canonical relative
polynomial defining the same field, hopefully with small coefficients.
Note that the equation is only canonical for a fixed nf, using a
different defining polynomial in the nf structure will produce a
different relative equation.
The binary digits of flag correspond to 1: add information to convert elements to the new representation, 2: absolute polynomial, instead of relative, 16: possibly use a suborder of the maximal order. More precisely:
0: default, return P
1: returns [P,a] where P is the default output and a,
a t_POLMOD
modulo P, is a root of pol.
2: returns Pabs, an absolute, instead of a relative, polynomial. This polynomial is canonical and does not depend on the nf structure. Same as but faster than
polredabs(rnfequation(nf, pol))
3: returns [Pabs,a,b], where Pabs is an absolute polynomial
as above, a, b are t_POLMOD
modulo Pabs, roots of nf.pol
and pol respectively.
16: (OBSOLETE) possibly use a suborder of the maximal order. This makes
rnfpolredabs
behave as rnfpolredbest
. Just use the latter.
Warning. The complexity of rnfpolredabs
is exponential in the absolute degree. The function rnfpolredbest
runs
in polynomial time, and tends to return polynomials with smaller
discriminants. It also supports polynomials with arbitrary coefficients in
nf, neither integral nor necessarily monic.
The library syntax is GEN rnfpolredabs(GEN nf, GEN pol, long flag)
.
Relative version of polredbest
. Given a polynomial pol
with coefficients in nf, finds a simpler relative polynomial P
defining the same field. As opposed to rnfpolredabs
this function does
not return a smallest (canonical) polynomial with respect to some
measure, but it does run in polynomial time.
The binary digits of flag correspond to 1: add information to convert elements to the new representation, 2: absolute polynomial, instead of relative. More precisely:
0: default, return P
1: returns [P,a] where P is the default output and a,
a t_POLMOD
modulo P, is a root of pol.
2: returns Pabs, an absolute, instead of a relative, polynomial. Same as but faster than
rnfequation(nf, rnfpolredbest(nf,pol))
3: returns [Pabs,a,b], where Pabs is an absolute polynomial
as above, a, b are t_POLMOD
modulo Pabs, roots of nf.pol
and pol respectively.
? K = nfinit(y^3-2); pol = x^2 +x*y + y^2; ? [P, a] = rnfpolredbest(K,pol,1); ? P %3 = x^2 - x + Mod(y - 1, y^3 - 2) ? a %4 = Mod(Mod(2*y^2+3*y+4,y^3-2)*x + Mod(-y^2-2*y-2,y^3-2), x^2 - x + Mod(y-1,y^3-2)) ? subst(K.pol,y,a) %5 = 0 ? [Pabs, a, b] = rnfpolredbest(K,pol,3); ? Pabs %7 = x^6 - 3*x^5 + 5*x^3 - 3*x + 1 ? a %8 = Mod(-x^2+x+1, x^6-3*x^5+5*x^3-3*x+1) ? b %9 = Mod(2*x^5-5*x^4-3*x^3+10*x^2+5*x-5, x^6-3*x^5+5*x^3-3*x+1) ? subst(K.pol,y,a) %10 = 0 ? substvec(pol,[x,y],[a,b]) %11 = 0
The library syntax is GEN rnfpolredbest(GEN nf, GEN pol, long flag)
.
Given an nf structure attached to a number field K, as output by
nfinit
, and a monic irreducible polynomial T in ℤK[x] defining a
relative extension L = K[x]/(T), computes the relative discriminant of L
and a pseudo-basis (A,J) for the maximal order ℤL viewed as a
ℤK-module. This is output as a vector [A,J,D,d], where D is the
relative ideal discriminant and d is the relative discriminant considered
as an element of K*/{K*}2.
? K = nfinit(y^2+1); ? [A,J,D,d] = rnfpseudobasis(K, x^2+y); ? A %3 = [1 0] [0 1] ? J %4 = [1, 1] ? D %5 = [0, -4]~ ? d %6 = [0, -1]~
Huge discriminants, helping rnfdisc. The format [T,B] is
also accepted instead of T and produce an order which is maximal at all
prime ideals specified by B, see ??rnfinit
.
? p = 585403248812100232206609398101; ? q = 711171340236468512951957953369; ? T = x^2 + 3*(p*q)^2; ? [A,J,D,d] = V = rnfpseudobasis(K, T); D time = 22,178 ms. %10 = 3 ? [A,J,D,d] = W = rnfpseudobasis(K, [T,100]); D time = 5 ms. %11 = 3 ? V == W %12 = 1 ? [A,J,D,d] = W = rnfpseudobasis(K, [T, [3]]); D %13 = 3 ? V == W %14 = 1
In this example, the results are identical since D ∩ ℤ factors over primes less than 100 (and in fact, over 3). Had it not been the case, the order would have been guaranteed maximal at primes 𝔭 | p for p ≤ 100 only (resp. 𝔭 | 3). And might have been nonmaximal at any other prime ideal 𝔭 such that 𝔭2 divided D.
The library syntax is GEN rnfpseudobasis(GEN nf, GEN T)
.
Given a nf attached to a number field K and a projective
module M given by a pseudo-matrix, returns a pseudo-basis (A,I)
(not in HNF in general) such that all the ideals of I except perhaps the
last one are equal to the ring of integers of nf. If M is a
polynomial with coefficients in K, replace it by the pseudo-matrix
returned by rnfpseudobasis
and return the four-component row vector
[A,I,D,d] where (A,I) are as before and (D,d) are discriminants
as returned by rnfpseudobasis
. The ideal class of the last ideal of
I is well defined; it is the Steinitz class of M (its image
in SK0(ℤK)).
The library syntax is GEN rnfsteinitz(GEN nf, GEN M)
.
Let F be the abelian number field contained in ℚ(ζf)
corresponding to the subgroup H of (ℤ/fℤ)*.
Computes the relative class number h−(F) = h(F)/h(F+) of F.
The argument fH
encodes F and the data [f,H] as follows:
* fH
= [f, H], where H is given by a vector of
integral generators,
* fH
= [bnr, H], where bnr is attached to
Clf(ℚ) and H is a congruence subgroup,
* fH
= [G, H], where G is idealstar
(f,1), and H is
a subgroup of (ℤ/fℤ)×,
* fH
= f, where we assume that H = {1}, i.e., F =
ℚ(ζf),
* an irreducible integral polynomial defining a primitive element for F.
The algorithm is based on an analytic class number formula: h−(F) = Q(F)w(F)∏K ⊂ FNℚ(ζ_{d)/ℚ} l(-B1,χ/2r) , where Q(F) is the unit index of F, w(F) is the number of roots of unity contained in F and K runs through all imaginary cyclic subfields of F. For each K, d is the degree [K:ℚ], χ is an arbitrary injective character of G(K/ℚ) to ℂ× and the Bernoulli number is given by B1,χ = (1/fχ)∑a = 1fχaχ(a) = -(1/(2-χ(2)) ∑1 ≤ a ≤ f_{χ/2}χ(a) , where fχ is the conductor of χ, namely the conductor of K. The unit index Q ∈ {1,2} is difficult to determine in general. If it could be computed, the function returns [a, b] = [h−, Q]; else it returns [2h−/Q, 0]. More precisely, the second component is 0 unless we are in one of the following cases:
* If f = pa with a prime number p, then Q = 1.
* If F = ℚ(ζf), then Q = 1 if and only if f = pa.
* If f = 4pa or paqb with odd prime numbers p,q, then Q = 1 if and only if [ℚ(ζf):F] is even.
Finally, the optional parameter p is an odd prime number.
If p is given, then subcyclohminus
outputs the valuation at p of
h−(F), in other words the maximal integer e such that
pe|h−(F) by evaluating p-adic valuations of Bernoulli numbers.
Since p is odd and Q ∈ {1,2}, the latter can be disregarded and
the result is the same as valuation(subcyclohminus(f,H)[1], p)
, but
adding this argument p can be much faster when p does not divide [F:ℚ]
or if a high power of p divides [F:ℚ].
? [a,b] = subcyclohminus(22220); b %1 = 2 \\ = Q ? sizedigit(a) %2 = 4306 \\ huge... ? valuation(a, 101) %3 = 41 ? subcyclohminus(22220, 101) \\ directly compute the valuation %4 = 41
shows that 10141 divides h−(ℚ(ζ22220)) exactly. Let kn be the n-th layer of the cyclotomic ℤ3-extension of k = ℚ(sqrt{-1501391}); the following computes en for 1 ≤ n ≤ 3, where 3en is the 3-part of the relative class number h−(kn):
? d = 1501391; ? subcyclohminus([9*d, [28,10,8]], 3) %1 = 5 ? subcyclohminus([27*d, [28,188,53]], 3) %2 = 12 ? subcyclohminus([81*d, [161,80,242]], 3) %3 = 26
Note that h+(kn) is prime to 3 for all n ≥ 0.
The following example computes the 3-part of h−(F), where F is the subfield of the 7860079-th cyclotomic field with degree 2.38.
? p=7860079; a=znprimroot(p)^(2*3^8); ? valuation(subcyclohminus([p,a])[1], 3) time = 1min, 47,896 ms. %2 = 65 ? subcyclohminus([p,a], 3) time = 1,290 ms. %3 = 65
The library syntax is GEN subcyclohminus(GEN fH, GEN p = NULL)
.
Let F be the abelian number field contained in ℚ(ζf) corresponding to the subgroup H of (ℤ/fℤ)*, let p > 2 be an odd prime not dividing [F:ℚ], let F oo be the cyclotomic ℤp-extension of F and let Fn by its n-th layer. Computes the minus part of Iwasawa polynomials and λ-invariants attached to F oo , using the Stickelberger elements ξnχ belonging to Fn.
The function is only implemented when p, n and f are relatively small:
all of p4, pn+1 and f must fit into an unsigned long
integer.
The argument fH
encodes the data [f,H] as follows:
* fH
= [f, H], where H is given by a vector of
integral generators,
* fH
= [bnr, H], where bnr is attached to
Clf(ℚ) and H is a congruence subgroup,
* fH
= [G, H], where G is idealstar
(f,1), and H is
a subgroup of (ℤ/fℤ)×,
* fH
= f, where we assume that H = {1}, i.e., F =
ℚ(ζf),
* an irreducible integral polynomial defining a primitive element for F.
If F is quadratic, we also allow p = 2 and more data is output (see below).
For a number field K, we write Kn for the n-th layer of the
cyclotomic ℤp-extension of K. The algorithm considers all cyclic
subfields K of F and all injective odd characters
χ:Gal(K/ℚ) ⟶
ℚp×. Let
Σn =
Gal(Kn/K), which is cyclic generated by the Frobenius automorphism
σ; we write Kχ = ℚp(χ),
𝒪χ = ℤp[χ] with maximal ideal 𝔭.
The Stickelberger element
ξnχ belongs to 𝒪χ[Σn];
the polynomial fnχ(x) ∈ 𝒪χ[x]
is constructed from ξnχ by the correspondence
σ ⟼
1+x. If n is sufficiently large, then
𝔭 does not divide fnχ(x) and the distinguished polynomial
gnχ(x) ∈ 𝒪χ[x] is uniquely determined by the relation
fnχ(x) = u(x)gnχ(x),u(x) ∈ 𝒪χ[x]×.
Owing to Iwasawa Main Conjecture proved by Mazur-Wiles, we can define
the Iwasawa polynomial
gχ(x) = limn ⟶
oo gnχ(x) ∈ 𝒪χ[x].
If r is the smallest integer satisfying
deg gnχ ≤ pr, then we have
gχ(x) = gnχ(x) (mod 𝔭n+1-r) .
Applying the norm from Kχ down to ℚp, we obtain polynomials
Gχ(x), Gnχ(x) ∈ ℤp[x] satisfying the congruence
Gχ(x) = Gnχ(x) (mod pn+1-r) .
Note that λp−(F) = ∑K,χ deg Gχ(x) is the Iwasawa
λ−-invariant of F, while the μ-invariant μp(F) is
known to be zero by the theorem of Ferrero-Washington.
If n = 0, the function returns [λp−(F)] (the vector may contain further useful components, see below); for positive n, it returns all non-constant Gnχ(x) mod {pn+1-r} as (K,χ) vary.
? subcycloiwasawa(22220, 41) \\ f = 22220, H = {1} %1 = [217] ? P = polcompositum(x^2 - 42853, polcyclo(5))[1]; ? subcycloiwasawa(P, 5) %3 = [3] ? subcycloiwasawa(P, 5, 4) \\ the sum of the degrees is indeed 3 %4 = [T + 585, T^2 + 405*T]
The first example corresponds to F = ℚ(ζ22220) and shows, that λ41−(F) = 217. The second one builds F = ℚ(sqrt{42853}, ζ5) then lists the non-constant G4χ(x) mod {p4} for p = 5. Note that in this case all degrees are ≤ 5 hence r ≤ 1 and n+1-r ≥ n; so the above also gives Gχ modulo p4.
We henceforth restrict to the quadratic case, where more information is available, and p = 2 is now allowed: we write F = ℚ(sqrt{d}) of discriminant d ( ! = 1) and character χ.
Algorithm and output for n = 0, F = ℚ(sqrt{d}). Currently, only the case d < 0 (F quadratic imaginary, i.e. χ(-1) = -1) is implemented.
* If p > 2, the function returns
[λ, ν, [e0,...,ek]], where λ = λp−(F),
pen denotes the p-part of the class number of Fn and en =
λ n + ν for all n > k. We use Gold's theorem
(Acta Arith. vol.26 (1974), pp. 21–32, vol.26 (1975), pp. 233–240).
Then as soon as en - en-1 < ϕ(pn) for some n ≥ 1, we have
λp(F) = en-en-1;
if χ(p) = 1 we can weaken the hypothesis to en-en-1 ≤
ϕ(pn) for some n ≥ 1 and obtain the same conclusion.
To compute en - en-1 we use Bernoulli numbers
(subcyclohminus
) if
χ(p) = 0 and a much faster algorithm of Gold
(Pacific J. Math. vol.40 (1972), pp.83–88) otherwise.
* For p = 2, we use Kida's formula (Tohoku Math. J. vol. 31 (1979), pp. 91–96) and only return [λ−].
When d > 1, subcycloiwasawa
should calculate
λp(F) = λp+(F), which is conjectured to be zero.
But this is not yet implemented.
? subcycloiwasawa(x^2+11111, 2) %1 = [5] /* λ2(ℚ(sqrt{-11111})) = 5 */ ? subcycloiwasawa(x^2+11111, 3) %2 = [1, 0, []] ? subcycloiwasawa(x^2+11111, 11) %3 = [0, 0, []]
This shows that for p = 3, we have λ = 1, ν = 0, and en = n for all n ≥ 0. And at p = 11, we have en = 0 for all n ≥ 0.
? subcycloiwasawa(x^2+1501391, 3) time = 23 ms. %4 = [14, -16, [2, 5]]
computes en by Gold's algorithm for F = ℚ(sqrt{-1501391}). This shows that at p = 3, we have λ = 14, ν = -16, then e0 = 2, e1 = 5, and en = 14n-16 for n ≥ 2.
? subcycloiwasawa(x^2+956238, 3) time = 141 ms. %5 = [14, -19, [1, 3]]
computes en using Bernoulli numbers for F = ℚ(sqrt{-956238}). This shows that e0 = 1, e1 = 3 and en = 14n-19 for n ≥ 2.
Algorithm and output for n > 0; F = ℚ(sqrt{d}).
* When d < 0 and n ≥ 1,
subcycloiwasawa
computes the Stickelberger element
ξn = ξnχ ∈ ℤp[Σn] and the Iwasawa polynomial
g(x) = gχ(x) ∈ ℤp[x]
from the n-th layer Fn of the cyclotomic ℤp-extension of F.
Let q be p (p odd) or 4 (p = 2) and let
q0 be the lcm of q and the discriminant d of F, and let
qn = q0pn.
Then Σn = Gal(ℚn/ℚ) = Gal(Fn/F)
= ⟨s>
,
where s is the Frobenius automorphism (ℚn/ℚ,1+q0) and
ξn = qn-1∑a = 1, (a,q_{n) = 1}qn
aχ(a)-1(ℚn/ℚ,a)-1
is an element of ℚ[Σn].
For (p,d) = (2,-1),(2,-2),(2,-3), (2,-6),(3,-3),
we know that λp(F) = 0 and there is nothing to do.
For the other cases, it is proved that (1/2)ξn ∈ ℤp[Σn].
The polynomial fn(x) ∈ ℤp[x] is constructed from (1/2)ξn
by the
correspondence s ⟼
1+x. If n is sufficiently large, then
p does not divide fn(x) and the distinguished polynomial
gn(x) ∈ ℤp[x] is uniquely determined by the relation
fn(x) = u(x)gn(x), u(x) ∈ ℤp[[x]]×. The Iwasawa polynomial
g(x) is defined by g(x) = limn ⟶
oo gn(x); if r is the
smallest integer satisfying deg g = λp(F) ≤ pr, then we have
g(x) = gn(x) (mod pn+1-r) when p > 2 and modulo 2n-r
otherwise.
Conjecturally, we have further
1. case q0 = p: ξn ∈ ℤ[Σn].
2. case d = -1 and χ(p) = -1: ξn ∈ ℤ[Σn].
3. case d = -3 and χ(p) = -1: (3/2)ξn ∈ ℤ[Σn].
4. other cases: (1/2)ξn ∈ ℤ[Σn].
Finally, subcycloiwasawa
outputs [g] where
g is gn(x) mod {pn+1-r} (p odd) or mod {2n-r} (p = 2).
? subcycloiwasawa(x^2+239, 3, 10) %6 = [x^6 + 18780*x^5 + 14526*x^4 + 18168*x^3 + 3951*x^2 + 1128*x]
This is g(x) mod {39}. Indeed, n = 10, λ = 6 (the degree), hence r = 2 and n + 1 - r = 2.
* When d > 1 and n ≥ 1, ξn* ∈ ℚ[Σn] is
constructed from
χ* = χ-1ω, where χ is the character of
F = ℚ(sqrt{d})
and ω is the Teichmüller character mod q. Next we construct
fn*(x) ∈ ℤp[x] from (1/2)ξn* by the correspondence
s-1 ⟼
(1+x)(1+q0)-1 and define the distinguished
polynomial gn*(x) ∈ ℤp[x] using fn*(x).
Then g*(x) = limn ⟶
oo gn*(x) is the Iwasawa
polynomial, which has a connection with Greenberg conjecture for F.
Let r be the smallest integer satisfying deg g* ≤ pr,
then we have g*(x) = gn*(x) (mod pn+1-r)
when p > 2 and g*(x) = gn*(x) (mod 2n-r) when p = 2.
Finally, subcycloiwasawa
outputs [g*] where
g* is gn*(x) mod {pn+1-r} (p odd) or mod {2n-r} (p = 2).
? subcycloiwasawa(x^2-13841, 2, 19) time = 1min, 17,238 ms. %7 = [x^3 + 30644*x^2 + 126772*x + 44128]
This is g*(x) mod {217} (r = 2), the distinguished polynomial treated in a paper of T. Fukuda, K. Komatsu, M. Ozaki and T. Tsuji (Funct. Approx. Comment. Math. vol.54.1, pp. 7–17, 2016).
The library syntax is GEN subcycloiwasawa(GEN fH, GEN p, long n)
.
Let F be the abelian number field contained in ℚ(ζf) corresponding to the subgroup H of (ℤ/fℤ)*, let p > 2 be an odd prime not dividing [F:ℚ]. Computes the p-Sylow subgroup AF of the ideal class group using an unconditional algorithm of M. Aoki and T. Fukuda (LNCS. vol.4076, pp.56–71, 2006).
The argument fH
encodes the data [f,H] as follows:
* fH
= [f, H], where H is given by a vector of
integral generators,
* fH
= [bnr, H], where bnr is attached to
Clf(ℚ) and H is a congruence subgroup,
* fH
= [G, H], where G is idealstar
(f,1), and H is
a subgroup of (ℤ/fℤ)×,
* fH
= f, where we assume that H = {1}, i.e., F =
ℚ(ζf),
* an irreducible integral polynomial defining a primitive element for F.
The result is a 6-component vector v, and components 2 or 3 can be left empty or only partially computed to save time (see flag below):
v[1] is p.
v[2] contains [E, [e1,...,ek]] with E = ∑i ei, meaning that the order of AF+ is pE and its cyclic structure is ℤ/pe1ℤ x...ℤ/pekℤ
v[3] similarly describes the order and the structure of AF−.
v[4] contains the structure of Gal(F/ℚ) as a product of cyclic groups (elementary divisors).
v[5] is the number of cyclic subfields K of F except for ℚ.
v[6] is the number of ℚp-conjugacy classes of injective
characters χ:Gal(K/ℚ) ⟶
ℚp×.
A vector of primes p is also accepted and the result is then a vector of vectors as above, in the same order as the primes.
The group AF is the direct sum of AF+ and AF−; each of AF+ and AF− is decomposed into χ-parts Aχ. By default, the function computes only |AF−| and an upper bound for |AF+| (expected to be equal to |AF+|) separately with different algorithms. This is expected to be fast. The behavior is controled by the binary digits of flag:
1: if |AF+| or |AF−| is computed, also determines its group structure and guarantees informations about AF+. This last part is usually costly.
2: do not compute quantities related to AF+ (the corresponding (ei) in v[2] is replaced with a dummy empty vector).
4: do not compute quantities related to AF− (the corresponding (ei) in v[3] is replaced with a dummy empty vector).
8: ignores proper subfields of F. This is motivated by the following kind of problems: let ℚ(pk) be the k-th layer of the cyclotomic ℤp-extension of ℚ and define ℚ(n) = ℚ(p1e1)...ℚ(prer) when n factors as n = p1e1...prer, which is a real cyclic field of degree n satisfying ℚ(n) ⊂ ℚ(m) when n | m. What are the prime factors of the class number h(n) of ℚ(n) ? The new prime factors of h(n), not occurring in a lower level, will all be present when using this flag.
The other values are technical and only useful when bit 1 (certification and structure) is set; do not set them unless you run into difficulties with default parameters.
16: when this bit is set, the function tries to save memory, sacrificing speed; this typically uses half the memory for a slowdown of a factor 2.
32: likely to speed up the algorithm when the rank of Aχ is large and to create a minor slowdown otherwise. Though the effect is restricted, the 3-class group of ℚ(sqrt{15338}, ζ5) is computed 4 times faster when this bit is set (see below).
Examples. With default flag = 0, the function (quickly) determines the exact value of |AF−| and a rigorous upper bound of |AF+| which is expected to be equal to |AF+|; of course, when the upper bound is 0, we know for sure that AF+ is trivial. With flag = 1 we obtain the group structure of AF completely and guarantee the informations about AF+ (slow).
? subcyclopclgp(22220, 101) time = 113 ms. %1 = [101, [0, []], [41, [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], [100, 20, 2, 2], 479, 7999]
This computes the 101-part AF of the ideal class group of
F = ℚ(ζ22220).
The output says that AF+ = 0, which is rigorous (since trivial),
and |AF− |= 10141, more precisely AF− is isomorphic to
(ℤ/101ℤ)41 which is also rigorous
(since the description of AF− is always rigorous). The Galois group
Gal(F/ℚ) is ℤ/100ℤ⨁ ℤ/20ℤ⨁ ℤ/2ℤ⨁ ℤ/2ℤ.
The field F has 479 cyclic subfields different from ℚ and
there are 7999 ℚ101-conjugacy classes of injective characters
χ:Gal(K/ℚ) ⟶
ℚ101×.
? subcyclopclgp(22220, 11) time = 83 ms. %2 = [11, [2, [1, 1]], [16, []], [100, 20, 2, 2], 479, 1799]
This computes the 11-part AF for the same F. The result says that |AF+ |= 112, AF+ is isomorphic to (ℤ/11ℤ)2 which is not rigorous and is only an upper bound, and |AF− |= 1116 which is rigorous. The group structure of AF− is unknown.
? subcyclopclgp(22220, 11, 1) time = 185 ms. %3 = [11, [2, [1, 1]], [16, [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]], [100, 20, 2, 2], 479, 1799]
now guarantees that AF+ is isomorphic to (ℤ/11ℤ)2 and determines that AF− is isomorphic to ℤ/112ℤ⨁ (ℤ/11ℤ)14, at the expense of slightly increasing the running time.
We now try a much harder example: F = ℚ(sqrt{36322},ζ5), which we could define using f = 726440 and H = [41, 61, 111, 131] (prove it!). We will use a defining polynomial instead:
? T = polcompositum(x^2-36322, polcyclo(5), 2); ? subcyclopclgp(T, 5) \\ fast when non rigorous for A^+ time = 82 ms. %4 = [5, [1, [1]], [4, []], [4, 2], 5, 7] \\ try to certify; requires about 2GB of memory ? subcyclopclgp(T, 5, 1) *** subcyclopclgp: the PARI stack overflows ! current stack size: 1000003072 (1907.352 Mbytes) ? default(parisizemax,"2G"); ? subcyclopclgp(T, 5, 1) \\ with more memory, we get an answer time = 36,201 ms. %6 = [5, [1, [1]], [4, [3, 1]], [4, 2], 5, 7] \\ trying to reduce memory use does not work (still need 2GB); slower ? subcyclopclgp(T, 5, 1+16) time = 39,450 ms.
This shows that AF+ is isomorphic to ℤ/5ℤ and AF− is isomorphic to ℤ/53ℤ⨁ ℤ/5ℤ for p = 5. For this example, trying to reduce memory use with flag = 1+16 fails: the computation becomes slower and still needs 2GB; flag = 1+16+32 is a disaster: it requires about 8GB and 9 minutes of computation.
Here's a situation where the technical flags make a difference: let F = ℚ(sqrt{15338}, ζ5).
? T = polcompositum(x^2-15338, polcyclo(5), 2); ? subcyclopclgp(T, 3) time = 123 ms. %2 = [3, [1, [1]], [4, []], [4, 2], 5, 5] ? subcyclopclgp(T, 3, 1) \\ requires a stack of 8GB time = 4min, 47,822 ms. %3 = [3, [1, [1]], [4, [1, 1, 1, 1]], [4, 2], 5, 5] ? subcyclopclgp(T, 3, 1+16); time = 7min, 20,876 ms. \\ works with 5GB, but slower ? subcyclopclgp(T, 3, 1+32); time = 1min, 11,424 ms. \\ also works with 5GB, 4 times faster than original ? subcyclopclgp(T, 3, 1+16+32); time = 1min, 47,285 ms. \\ now works with 2.5GB
Let F = ℚ(106) defined as above; namely, F is the composite field of ℚ(sqrt{2}) and the subfield of ℚ(ζ532) with degree 53. This time we shall build the compositum using class field theory:
? Q = bnfinit(y); ? bnr1 = bnrinit(Q, 8); H1 = Mat(2); ? bnr2 = bnrinit(Q, [53^2, [1]]); H2 = Mat(53); ? [bnr,H] = bnrcompositum([bnr1, H1], [bnr2, H2]); ? subcyclopclgp([bnr,H], 107) time = 10 ms. %5 = [107, [1, [1]], [0, []], [106], 3, 105] ? subcyclopclgp([bnr,H], 107, 1) \\ requires 2.5GB time = 15min, 13,537 ms. %6 = [107, [1, [1]], [0, []], [106], 3, 105]
Both results are identical (and they were expected to be), but only the second is rigorous. Flag bit 32 has a minor impact in this case (reduces timings by 20 s.)
The library syntax is GEN subcyclopclgp(GEN fH, GEN p, long flag)
.
cyc being a vector of positive integers giving the cyclic
components for a finite Abelian group G (or any object which has a
.cyc
method), outputs the list of subgroups of G. Subgroups are
given as HNF left divisors of the SNF matrix corresponding to G.
If flag = 0 (default) and cyc is a bnr structure output by
bnrinit
, gives only the subgroups whose modulus is the conductor.
Otherwise, all subgroups are given.
If bound is present, and is a positive integer, restrict the output to subgroups of index less than bound. If bound is a vector containing a single positive integer B, then only subgroups of index exactly equal to B are computed. For instance
? subgrouplist([6,2]) %1 = [[6, 0; 0, 2], [2, 0; 0, 2], [6, 3; 0, 1], [2, 1; 0, 1], [3, 0; 0, 2], [1, 0; 0, 2], [6, 0; 0, 1], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] ? subgrouplist([6,2],3) \\ index less than 3 %2 = [[2, 1; 0, 1], [1, 0; 0, 2], [2, 0; 0, 1], [3, 0; 0, 1], [1, 0; 0, 1]] ? subgrouplist([6,2],[3]) \\ index 3 %3 = [[3, 0; 0, 1]] ? bnr = bnrinit(bnfinit(x), [120,[1]], 1); ? L = subgrouplist(bnr, [8]);
In the last example, L corresponds to the 24 subfields of ℚ(ζ120), of degree 8 and conductor 120 oo (by setting flag, we see there are a total of 43 subgroups of degree 8).
? vector(#L, i, galoissubcyclo(bnr, L[i]))
will produce their equations. (For a general base field, you would
have to rely on bnrstark
, or bnrclassfield
.)
Warning. This function requires factoring the exponent of G.
If you are only interested in subgroups of index n (or dividing n), you
may considerably speed up the function by computing the subgroups of
G/Gn, whose cyclic components are apply(x- > gcd(n,x), C)
(where
C gives the cyclic components of G). If you want the bnr variant,
now is a good time to use bnrinit(,,, n)
as well, to directly compute
the ray class group modulo n-th powers.
The library syntax is GEN subgrouplist0(GEN cyc, GEN bound = NULL, long flag)
.