Catalogue of GP/PARI Functions: General number fields
Author: Karim Belabas
Keywords: PARI, GP, DOC

## General number fields

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).

#### Number field structures

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.

#### Algebraic numbers and ideals

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 non-negative 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`, `idealsqr`, `idealinv`, `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.

#### Finite abelian groups

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 ∏ 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 χ(∏ gjnj) = exp(2π i∑ 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).

#### Relative extensions

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.

#### Class field theory

A modulus, in the sense of class field theory, is a divisor supported on the non-complex 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.

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!

#### General use

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` (bnr, 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` (bnr, 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` (bnr, 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.

Deprecated. The following member functions are still available, but deprecated and should not be used in new scripts :

`futu` (bnr, bnf, ) : [u1,...,ur,w], (ui) is a vector of fundamental units,

w generates the torsion units.

`tufu` (bnr, bnf, ) : [w,u1,...,ur], (ui) is a vector of fundamental units,

w generates the torsion units.

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`.

#### Class group, units, and the GRH

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 non-monic 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 non-negative 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 Bach says that c2 = 12 is always suitable, but this bound is very pessimistic and a direct algorithm due to Belabas-Diaz-Friedman 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.

#### bnfcertify(bnf, {flag = 0})

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: missing units in bnf.
      ? 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).

#### bnfcompress(bnf)

Computes a compressed version of bnf (from `bnfinit`), a "small Buchmann's number field" (or sbnf for short) which contains enough information to recover a full bnf vector very rapidly, but which is much smaller and hence easy to store and print. Calling `bnfinit` on the result recovers a true `bnf`, in general different from the original. Note that an snbf is useless for almost all purposes besides storage, and must be converted back to bnf form before use; for instance, no `nf*`, `bnf*` or member function accepts them.

An sbnf is a 12 component vector v, as follows. Let `bnf` be the result of a full `bnfinit`, complete with units. Then v[1] is `bnf.pol`, v[2] is the number of real embeddings `bnf.sign[1]`, v[3] is `bnf.disc`, v[4] is `bnf.zk`, v[5] is the list of roots `bnf.roots`, v[7] is the matrix `W` = `bnf[1]`, v[8] is the matrix `matalpha` = `bnf[2]`, v[9] is the prime ideal factor base `bnf[5]` coded in a compact way, and ordered according to the permutation `bnf[6]`, v[10] is the 2-component vector giving the number of roots of unity and a generator, expressed on the integral basis, v[11] is the list of fundamental units, expressed on the integral basis, v[12] is a vector containing the algebraic numbers alpha corresponding to the columns of the matrix `matalpha`, expressed on the integral basis.

All the components are exact (integral or rational), except for the roots in v[5].

The library syntax is `GEN bnfcompress(GEN bnf)`.

#### bnfdecodemodule(nf, m)

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[1][2]
      %1 = [[Mat([8, 1]), [[0, 0, 0]]], [Mat([9, 1]), [[0, 0, 0]]]]
      ? bnfdecodemodule(K, s[1][1])
      %2 =
      [2 0]

      [0 1]

The library syntax is `GEN decodemodule(GEN nf, GEN m)`.

#### bnfinit(P, {flag = 0}, {tech = []})

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.

If the precision becomes insufficient, `gp` does not strive to compute the units by default (flag = 0).

When flag = 1, we insist on finding the fundamental units exactly. Be warned that this can take a very long time when the coefficients of the fundamental units on the integral basis are very large. If the fundamental units are simply too large to be represented in this form, an error message is issued. They could be obtained using the so-called compact representation of algebraic numbers as a formal product of algebraic integers. The latter is implemented internally but not publicly accessible yet.

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 or sbnf are technical and never used by the casual user. 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] used to contain a permutation of the prime factor base, but has been obsoleted. It 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`, a 1 (used to contain an obsolete "check number"), the number of roots of unity and a generator `bnf.tu`, the fundamental units `bnf.fu`.

bnf[9] is a 3-element row 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].

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` (insist on finding fundamental units). The function `GEN Buchall_param(GEN P, double c1, double c2, long nrpid, long flag, long prec)` gives direct access to the technical parameters.

#### bnfisintnorm(bnf, x)

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.

See also `bnfisnorm`.

The library syntax is `GEN bnfisintnorm(GEN bnf, GEN x)`. The function `GEN bnfisintnormabs(GEN bnf, GEN a)` 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.

#### bnfisnorm(bnf, x, {flag = 1})

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, set flag = 0 (in this case, x is a norm iff b = 1). If flag is non zero 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 12log(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)`.

#### bnfisprincipal(bnf, x, {flag = 1})

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 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 much 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.

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) and `nf_FORCE` (insist on finding the generators).

#### bnfissunit(bnf, sfu, x)

bnf being output by `bnfinit`, sfu by `bnfsunit`, gives the column vector of exponents of x on the fundamental S-units and the roots of unity, in the following order: the fundamental units bnf.fu, the root of unity bnf.tu, and the S-units sfu[1]. If x is not an S-unit, outputs an empty vector.

       ? 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
       ? sfu = bnfsunit(bnf,S);
       ? sfu[1]
       %5 = [-5/6*x^3 + 4/3*x^2 - 4/3*x - 3/2, 5]
       ? u = [10,-40,24,11]~;
       ? bnfissunit(bnf,sfu,u)
       %7 = [1, Mod(2, 6), 2, 0]~
       ? bnfissunit(bnf,sfu,3)
       %8 = []~

The library syntax is `GEN bnfissunit(GEN bnf, GEN sfu, GEN x)`.

#### bnfisunit(bnf, 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 for i ≤ r and is an integer modulo the order of ζ for i = r+1.

Note that bnf need not contain the fundamental unit explicitly:

      ? setrand(1); bnf = bnfinit(x^2-x-100000);
      ? bnf.fu
        ***   at top-level: bnf.fu
        ***                     ^--
        *** _.fu: missing units in .fu.
      ? u = [119836165644250789990462835950022871665178127611316131167, \
             379554884019013781006303254896369154068336082609238336]~;
      ? bnfisunit(bnf, u)
      %3 = [-1, Mod(0, 2)]~

The given u is the inverse of the fundamental unit implicitly stored in bnf. In this case, the fundamental unit was not computed and stored in algebraic form since the default accuracy was too low. (Re-run the command at \g1 or higher to see such diagnostics.)

The library syntax is `GEN bnfisunit(GEN bnf, GEN x)`.

#### bnflog(bnf, l)

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)`.

#### bnflogdegree(nf, A, 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 + 2^2) 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)`.

#### bnflogef(nf, pr)

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 ℚp^c/ℚp be the cyclotomic ℤp-extension, then ~{e} = [F_𝔭 : F_𝔭 ∩ ℚp^c] and ~{f} = [F_𝔭 ∩ ℚp^c : ℚ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)`.

#### bnfnarrow(bnf)

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)`.

#### bnfsignunit(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 bnf.tufu */
      tpuexpo(bnf)=
      { my(K, S = bnfsignunit(bnf), [m,n] = matsize(S));
        \\ m = bnf.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)
        K = matker(S * Mod(1,2));
        if (K, mathnfmodid(lift(K), 2), 2*matid(n+1))
      }

      /* totally positive fundamental units */
      tpu(bnf)=
      { my(ex = tpuexpo(bnf)[,2..-1]); \\ remove ex[,1], corresponds to 1 or -1
        vector(#ex, i, nffactorback(bnf, bnf.tufu, ex[,i]));
      }

The library syntax is `GEN signunits(GEN bnf)`.

#### bnfsunit(bnf, S)

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 empty vector (used to give the logarithmic embeddings of the generators in v[1] in version 2.0.16).

v[4] is the S-regulator (this is the product of the regulator, the determinant of v[2] and the natural logarithms of the norms of the ideals in S).

v[5] gives the S-class group structure, in the usual format (a row 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)`.

#### bnrL1(bnr, {H}, {flag = 0})

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.s^r + 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 non-zero 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 non-zero 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)`.

#### bnrchar(bnr, g, {v})

Returns all characters χ on `bnr.clgp` such that χ(gi) = e(vi), where e(x) = exp(2iπ x). 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 ideals in any form, and each vi is a rational number whose denominator must divide the order of gi in the ray class group. For convenience, the vector of the gi can be replaced by a matrix whose columns give their discrete logarithm, as given by `bnrisprincipal`; this allows to specify abstractly a subgroup of the ray class group.

      ? bnr = bnrinit(bnfinit(x), [160,[1]], 1); /* (Z/160Z)* */
      ? bnr.cyc
      %2 = [8, 4, 2]
      ? g = bnr.gen;
      ? bnrchar(bnr, g, [1/2,0,0])
      %4 = [[4, 0, 0]]  \\ a unique character
      ? bnrchar(bnr, [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(bnr, [1,0,0;0,1,0;0,0,2])
      %6 = [[0, 0, 1], [0, 0, 0]]  \\ characters trivial on given subgroup

The library syntax is `GEN bnrchar(GEN bnr, GEN g, GEN v = NULL)`.

#### bnrclassno(A, {B}, {C})

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.

#### bnrclassnolist(bnf, list)

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)`.

#### bnrconductor(A, {B}, {C}, {flag = 0})

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].

The library syntax is `GEN bnrconductor0(GEN A, GEN B = NULL, GEN C = NULL, long flag)`.

Also available is `GEN bnrconductor(GEN bnr, GEN H, long flag)`

#### bnrconductorofchar(bnr, chi)

This function is obsolete, use bnrconductor.

The library syntax is `GEN bnrconductorofchar(GEN bnr, GEN chi)`.

#### bnrdisc(A, {B}, {C}, {flag = 0})

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)`.

#### bnrdisclist(bnf, bound, {arch})

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.n^2+(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)`.

#### bnrgaloisapply(bnr, mat, H)

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)`.

#### bnrgaloismatrix(bnr, aut)

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`. aut can be given as a polynomial, an algebraic number, or a vector of automorphisms or a Galois group as output by `galoisinit`, in which case a vector of matrices is returned (in the later case, only for the generators `aut.gen`).

See `bnrisgalois` for an example.

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.

#### bnrinit(bnf, f, {flag = 0})

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`.)

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 computed, which saves time. Hence `bnr.gen` would produce an error.

If flag = 1, as the default, except that generators are computed.

The library syntax is `GEN bnrinit0(GEN bnf, GEN f, long flag)`. Instead the above hardcoded numerical flags, one should rather use `GEN Buchray(GEN bnf, GEN module, long flag)` where 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.

#### bnrisconductor(A, {B}, {C})

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)`.

#### bnrisgalois(bnr, gal, H)

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);
      G=galoisinit(K);
      B=bnrinit(K,9,1);
      L1=[H|H<-subgrouplist(B,3), bnrisgalois(B,G,H)]
      ##
      M=bnrgaloismatrix(B,G)
      L2=[H|H<-subgrouplist(B,3), bnrisgalois(B,M,H)]
      ##

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)`.

#### bnrisprincipal(bnr, x, {flag = 1})

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.

If flag = 1, returns a 2-component vector v where v[1] is the vector of components of x on the ray class group generators, v[2] is an element α congruent to 1 mod* f such that x = α ∏i gixi.

If flag = 0, outputs only v1. In that case, 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 define canonical generators attached to the `bnr` and compute with respect to them.

      ? 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]; \\ a prime ideal above 3
      ? bnrisprincipal(bnr,P)
      %4 = [[1, 0, 0]~, 1]
      ? bnrisprincipal(bnr,P, 0) \\ omit the principal part
      %4 = [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)

#### bnrrootnumber(bnr, chi, {flag = 0})

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 χ(g1^ag2^b) = ζ12aζ2^b. 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)`.

#### bnrstark(bnr, {subgroup})

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

      rnfpolredabs(bnf, pol, 16)     \\  compute a reduced relative polynomial
      rnfpolredabs(bnf, pol, 16 + 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. It was decided that it was more useful to keep the extra information thus made available, hence the user has to take the compositum herself.

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 `rnfkummer`:

      ? 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.
      ? lift( rnfkummer(bnr) )
      time = 24 ms.
      %2 = x^2 + (1/3*y^6 - 11/3*y^4 + 8*y^2 - 5)

The library syntax is `GEN bnrstark(GEN bnr, GEN subgroup = NULL, long prec)`.

#### dirzetak(nf, b)

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)`.

#### factornf(x, t)

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 non-rational 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)`.

#### galoischardet(gal, chi, {o = 1})

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)`.

#### galoischarpoly(gal, chi, {o = 1})

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)`.

#### galoischartable(gal)

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)`.

#### galoisconjclasses(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)`.

#### galoisexport(gal, {flag})

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)`.

#### galoisfixedfield(gal, perm, {flag}, {v = y})

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 x^4+1 = (x^2-sqrt{2}x+1)(x^2+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.

#### galoisgetgroup(a, {b})

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.

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.

#### galoisgetname(a, b)

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. It is possible for different groups to have the same name. The command below outputs the names of all abstract groups of order 12:

      ? N = galoisgetgroup(12); \\ # of abstract groups of order 12
      ? for(i=1, N, print(i,":",galoisgetname(12,i)))
      1:C3 : C4
      2:C12
      3:A4
      4:D12
      5:C6 x C2

The library syntax is `GEN galoisgetname(long a, long b)`.

#### galoisgetpol(a, {b}, {s})

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 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.

#### galoisidentify(gal)

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)`.

#### galoisinit(pol, {den})

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 36 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 or S4.

In practice, almost all small groups are WKSS, the exceptions having order 36(1 exception), 48(2), 56(1), 60(1), 72(5), 75(1), 80(1), 96(10) and ≥ 108.

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 = p^e (`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].

* for 1 ≤ i ≤ g the subgroup of G generated by [s1,...,sg] is normal, with the exception of i = g-2 in the A4 case and of i = g-3 in the SA 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)`.

#### galoisisabelian(gal, {flag = 0})

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 fl = 0, 1 if fl = 1.

This command also accepts subgroups returned by `galoissubgroups`.

The library syntax is `GEN galoisisabelian(GEN gal, long flag)`.

#### galoisisnormal(gal, subgrp)

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)`.

#### galoispermtopol(gal, perm)

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)`.

#### galoissubcyclo(N, H, {fl = 0}, {v})

Computes the subextension 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).

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 fl = 0, compute a polynomial (in the variable v) defining the subfield of ℚ(ζn) fixed by the subgroup H of (ℤ/nℤ)*.

If fl = 1, compute only the conductor of the abelian extension, as a module.

If fl = 2, output [pol, N], where pol is the polynomial as output when fl = 0 and N the conductor as output when fl = 1.

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 fl, long v = -1)` where `v` is a variable number.

#### galoissubfields(G, {flag = 0}, {v})

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.

#### galoissubgroups(G)

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)`.

#### idealadd(nf, x, y)

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: non-square t_MAT in idealtyp.
        ? c = [2, 0; 2, 0]; idealadd(K, c, c)   \\ non-sense
        %6 =
        [2 0]

        [0 2]
        ? d = [1, 0; 0, 2]; idealadd(K, d, d)   \\ non-sense
        %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 OK-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)`.

#### idealaddtoone(nf, x, {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)`.

#### idealappr(nf, x, {flag})

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 non-zero, 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.

#### idealchinese(nf, x, {y})

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 non-zero.

      ? 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.

      ? 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`.

#### idealcoprime(nf, x, y)

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.

The library syntax is `GEN idealcoprime(GEN nf, GEN x, GEN y)`.

#### idealdiv(nf, x, y, {flag = 0})

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 non-zero, 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).

#### idealfactor(nf, x, {lim})

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 x)` or `GEN idealfactor_limit(GEN x, ulong lim)`.

#### idealfactorback(nf, f, {e}, {flag = 0})

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 non-zero, 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)`.

#### idealfrobenius(nf, gal, pr)

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) = x^p 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)`.

#### idealhnf(nf, u, {v})

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 b 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 b^2 - 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)`.

#### idealintersect(nf, A, B)

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)`.

#### idealinv(nf, x)

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)`.

#### idealispower(nf, A, n, {&B})

Let nf be a number field and n > 0 be a positive integer. Return 1 if the fractional ideal A = B^n 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)`.

#### ideallist(nf, bound, {flag = 4})

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, depending on the value of flag:

The possible values of flag are:

0: give the bid attached to the ideals, without generators.

1: as 0, but include the generators in the bid.

2: in this case, nf must be a bnf with units. Each component is of the form [bid,U], where bid is as case 0 and U is a vector of discrete logarithms of the units. More precisely, it gives the `ideallog`s with respect to bid of `bnf.tufu`. This structure is technical, and only meant to be used in conjunction with `bnrclassnolist` or `bnrdisclist`.

3: as 2, but include the generators in the bid.

4: give only the HNF of the ideal.

      ? 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 4 in ℤ[i]

If one wants more information, one could do instead:

      ? nf = nfinit(x^2+1);
      ? L = ideallist(nf, 100, 0);
      ? l = L[25]; vector(#l, i, l[i].clgp)
      %3 = [[20, [20]], [16, [4, 4]], [20, [20]]]
      ? l[1].mod
      %4 = [[25, 18; 0, 1], []]
      ? l[2].mod
      %5 = [[5, 0; 0, 5], []]
      ? l[3].mod
      %6 = [[25, 7; 0, 1], []]

where we ask for the structures of the (ℤ[i]/I)* 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.

The library syntax is `GEN ideallist0(GEN nf, long bound, long flag)`.

#### ideallistarch(nf, list, arch)

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)`.

#### ideallog({nf}, x, bid)

nf is a number field, bid is as output by `idealstar(nf, D,...)` and x a non-necessarily integral element of nf which must have valuation equal to 0 at all prime ideals in the support of `D`. 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 is `GEN Zideallog(GEN bid, GEN x)` when `nf` is `NULL`.

#### idealmin(nf, ix, {vdir})

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)`.

#### idealmul(nf, x, y, {flag = 0})

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 non-zero, 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).

#### idealnorm(nf, x)

Computes the norm of the ideal x in the number field nf.

The library syntax is `GEN idealnorm(GEN nf, GEN x)`.

#### idealnumden(nf, 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)`.

#### idealpow(nf, x, k, {flag = 0})

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 [I^k, t^k].

If flag is non-zero, 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)`.

#### idealprimedec(nf, p, {f = 0})

Computes the prime ideal decomposition of the (positive) prime number p in the number field K represented by nf. If a non-prime p is given the result is undefined. If f is present and non-zero, 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 the algebraic integer b is 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)`.

#### idealprincipalunits(nf, pr, k)

Given a prime ideal in `idealprimedec` format, returns the multiplicative group (1 + pr) / (1 + pr^k) 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)`.

#### idealramgroups(nf, gal, pr)

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 follow:

* `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 non-trivial 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)`.

#### idealred(nf, I, {v = 0})

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 non-negative 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 non-trivial result does not prove that the ideal is non-principal. 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 ||v^2 = ∑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)`.

#### idealredmodpower(nf, x, n, {B = primelimit})

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 b^n = 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 J^n 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)`.

#### idealstar({nf}, N, {flag = 1})

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`.

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 idealstar0(GEN nf = NULL, GEN N, long flag)`. Instead the above hardcoded numerical flags, one should rather use `GEN Idealstar(GEN nf, GEN ideal, long flag)`, 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.

#### idealtwoelt(nf, x, {a})

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 non-zero 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)`.

#### idealval(nf, x, pr)

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.

#### matalgtobasis(nf, 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 `nfalgtobasis` to each entry of x.

The library syntax is `GEN matalgtobasis(GEN nf, GEN x)`.

#### matbasistoalg(nf, 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)`.

#### modreverse(z)

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 x^3 - 5x^2 + 4x -1 is another defining polynomial for the cubic field ℚ(u) = ℚ[x]/(x^3 - x - 1) = ℚ[x]/(x^3 - 5x^2 + 4x - 1) = ℚ(v), and that u → v^2 - 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)`.

#### newtonpoly(x, p)

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)`.

#### nfalgtobasis(nf, x)

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)`.

#### nfbasis(T)

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. The basis elements are given as elements in ℚ[X]/(T):

      ? nfbasis(x^2 + 1)
      %1 = [1, x]

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 10^5, 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 is actually a global integral basis if all prime divisors of the field discriminant are included! 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.

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 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 will still be a correct integral basis if the field discriminant factors completely over the actual primes in the list. Adding a composite C such that C^2 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 non-trivial zero divisor, thereby factoring C and we go on with the refined factorization. (Note that including a C such that C^2 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;
      ? P = factor(poldisc(T), B)[,1]; \\ primes <= B dividing D + cofactor
      ? basis = nfbasis([T, listP])
      ? disc = nfdisc([T, listP])

We obtain the maximal order and its discriminant if the field discriminant factors completely over the primes less than B (together with the primes contained in the `addprimes` table). This can be tested as follows:

        check = factor(disc, B);
        lastp = check[-1..-1,1];
        if (lastp > B && !setsearch(addprimes(), lastp),
          warning("nf may be incorrect!"))

This is a sufficient but not a necessary condition, hence the warning, instead of an error. N.B. `lastp` is the last entry in the first column of the `check` matrix, i.e. the largest prime dividing `nf.disc` if ≤ B or if it belongs to the prime table.

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 = nf.zk;
      ? disc = nf.disc;

The library syntax is `nfbasis(GEN T, GEN *d, GEN listP = NULL)`, which returns the order basis, and where `*d` receives the order discriminant.

#### nfbasistoalg(nf, x)

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)`.

#### nfcertify(nf)

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)`.

#### nfcompositum(nf, P, Q, {flag = 0})

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)`.

#### nfdetint(nf, x)

Given a pseudo-matrix x, computes a non-zero 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)`.

#### nfdisc(T)

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 library syntax is `nfdisc(GEN T)` (`listP = NULL`). Also available is `GEN nfbasis(GEN T, GEN *d, GEN listP = NULL)`, which returns the order basis, and where `*d` receives the order discriminant.

#### nfeltadd(nf, x, y)

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)`.

#### nfeltdiv(nf, x, 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)`.

#### nfeltdiveuc(nf, x, 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)`.

#### nfeltdivmodpr(nf, x, y, pr)

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.

#### nfeltdivrem(nf, x, y)

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)`.

#### nfeltembed(nf, x, {pl})

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)`.

#### nfeltmod(nf, x, y)

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)`.

#### nfeltmul(nf, x, 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)`.

#### nfeltmulmodpr(nf, x, y, pr)

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.

#### nfeltnorm(nf, x)

Returns the absolute norm of x.

The library syntax is `GEN nfnorm(GEN nf, GEN x)`.

#### nfeltpow(nf, x, k)

Given an element x in nf, and a positive or negative integer k, computes x^k 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.

#### nfeltpowmodpr(nf, x, k, pr)

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 x^k 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.

#### nfeltreduce(nf, a, id)

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)`.

#### nfeltreducemodpr(nf, x, pr)

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.

#### nfeltsign(nf, x, {pl})

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)`.

#### nfelttrace(nf, x)

Returns the absolute trace of x.

The library syntax is `GEN nftrace(GEN nf, GEN x)`.

#### nfeltval(nf, x, pr, {&y})

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`).

#### nffactor(nf, T)

Factorization of the univariate polynomial 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)`.

#### nffactorback(nf, f, {e})

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)`.

#### nffactormod(nf, Q, pr)

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)`.

#### nfgaloisapply(nf, aut, x)

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 non-trivial 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)`.

#### nfgaloisconj(nf, {flag = 0}, {d})

nf being a number field as output by `nfinit`, computes the conjugates of a root r of the non-constant 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.

#### nfgrunwaldwang(nf, Lpr, Ld, pl, {v = 'x})

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, 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.

#### nfhilbert(nf, a, b, {pr})

If pr is omitted, compute the global quadratic Hilbert symbol (a,b) in nf, that is 1 if x^2 - a y^2 - b z^2 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 bnf,GEN a,GEN b)` (global quadratic Hilbert symbol).

#### nfhnf(nf, x, {flag = 0})

Given a pseudo-matrix (A,I), finds a pseudo-basis (B,J) in Hermite normal form of the module it generates. If flag is non-zero, 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 non-principal.

#### nfhnfmod(nf, x, detx)

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)`.

#### nfinit(pol, {flag = 0})

pol being a non-constant, preferably monic, irreducible polynomial in ℤ[X], initializes a number field structure (`nf`) 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 useful for certain computations in the number field K.

* 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.

* Finally, 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). MDI is only used in `idealinv`.

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 an integral basis for ℤK (`nf.zk`) expressed on the powers of θ. 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 n^2 matrix giving the multiplication table of the integral basis.

If a non monic polynomial is input, `nfinit` will transform it into a monic one, then reduce it (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]  \\   𝔭2^3

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 special input format [pol, B] is also accepted where pol is a polynomial as above and B has one of the following forms

* an integer basis, as would be computed by `nfbasis`: a vector of polynomials with first element 1. This is useful if the maximal order is known in advance.

* an argument `listP` which specifies a list of primes (see `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 is unconditionaly correct when the discriminant `nf.disc` factors completely over this set of primes. 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 ≤ 10^3 (no prime ≤ 10^3 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.

If flag = 2: pol is changed into another polynomial P defining the same number field, which is as simple as can easily be found using the `polredbest` algorithm, and all the subsequent computations are done using this new polynomial. In particular, the first component of the result is the modified polynomial.

If flag = 3, apply `polredbest` as in case 2, but outputs [nf,`Mod`(a,P)], where nf is as before and `Mod`(a,P) = `Mod`(x,pol) gives the change of variables. This is implicit when pol is not monic: first a linear change of variables is performed, to get a monic polynomial, then `polredbest`.

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

`GEN nfinitall(GEN x, long flag, long prec)`, where flag is an or-ed combination of

* `nf_RED`: find a simpler defining polynomial,

* `nf_ORIG`: if `nf_RED` set, also return the change of variable,

* `nf_ROUND2`: Deprecated. Slow down the routine by using an obsolete normalization algorithm (do not use this one!),

* `nf_PARTIALFACT`: Deprecated. Lazy factorization of the polynomial discriminant. Result is conditional unless `nfcertify` can certify it.

#### nfisideal(nf, x)

Returns 1 if x is an ideal in the number field nf, 0 otherwise.

The library syntax is `long isideal(GEN nf, GEN x)`.

#### nfisincl(f, g)

Let f and g define number fields, where f and g are irreducible polynomials in ℚ[X] and nf structures as output by `nfinit`. Tests whether the number field f is conjugate to a subfield of the field g. If they are not, the output is the integer 0. If they are, the output is a vector of polynomials, each polynomial a representing an embedding i.e. being such that g | f o a. If either f or g is not irreducible, the result is undefined.

      ? T = x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10;
      ? U = x^3 + 3*x^2 + 3*x - 2

      ? v = nfisincl(U, T);
      %2 = [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(v[1],T))
      %3 = Mod(0, x^6 + 3*x^4 - 6*x^3 + 3*x^2 + 18*x + 10)
      ? #nfisincl(x^2+1, T) \\ two embeddings
      %4 = 2

      \\ same result with nf structures
      ? nfisincl(U, L = nfinit(T)) == v
      %5 = 1
      ? nfisincl(K = nfinit(U), T) == v
      %6 = 1
      ? nfisincl(K, L) == v
      %7 = 1

      \\ comparative bench: an nf is a little faster, esp. for the subfield
      ? B = 10^3;
      ? for (i=1, B, nfisincl(U,T))
      time = 712 ms.

      ? for (i=1, B, nfisincl(K,T))
      time = 485 ms.

      ? for (i=1, B, nfisincl(U,L))
      time = 704 ms.

      ? for (i=1, B, nfisincl(K,L))
      time = 465 ms.

Using an nf structure for the potential 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 = 308 ms.

The library syntax is `GEN nfisincl(GEN f, GEN g)`.

#### nfisisom(f, g)

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 non-isomorphic, 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)`.

#### nfislocalpower(nf, pr, a, n)

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)`.

#### nfkermodpr(nf, x, pr)

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.

#### nfmodpr(nf, x, pr)

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);
      ? 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]

The library syntax is `GEN nfmodpr(GEN nf, GEN x, GEN pr)`.

#### nfmodprinit(nf, 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 library syntax is `GEN nfmodprinit(GEN nf, GEN pr)`.

#### nfmodprlift(nf, x, pr)

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)`.

#### nfnewprec(nf)

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 or a bnr (update structure to current precision) but may be quite slow: many generators of principal ideals have to be computed; note that in this latter case, the bnf must contain 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)`.

#### nfpolsturm(nf, T, {pl})

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)`.

#### nfroots({nf}, x)

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`.

#### nfrootsof1(nf)

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.

      ? 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 rootsof1(GEN nf)`. Also available is `GEN rootsof1_kannan(GEN nf)`, that computes all algebraic integers of T2 norm equal to the field degree (all roots of 1, by Kronecker's theorem). This is in general a little faster than the default when there are roots of 1 in the field (say twice faster), but can be much slower (say, days slower), since the algorithm is a priori exponential in the field degree.

#### nfsnf(nf, x, {flag = 0})

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 non-zero 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 K^n (with canonical basis (e1,...,en)). This data defines the ℤK module x given by (b_1e1⨁ ...⨁ b_nen) / (a_1A1⨁ ...⨁ a_nAn) , 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).

#### nfsolvemodpr(nf, a, b, P)

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.

#### nfsplitting(P, {d})

Defining polynomial over ℚ for the splitting field of P, that is the smallest field over which P is totally split. If 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.

      ? 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]

Specifying the degree of the splitting field can make the computation faster.

      ? 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.

The library syntax is `GEN nfsplitting(GEN P, GEN d = NULL)`.

#### nfsubfields(pol, {d = 0})

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], 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 J. Klüners's algorithm in the general case, and B. Allombert's `galoissubfields` when nf is Galois (with weakly supersolvable Galois group).

The library syntax is `GEN nfsubfields(GEN pol, long d)`.

#### polcompositum(P, Q, {flag = 0})

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, x^5-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).

#### polgalois(T)

Galois group of the non-constant polynomial T ∈ ℚ[X]. In the present version 2.12.1, 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.

#### polred(T, {flag = 0})

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` = 10^5 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[2,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.

#### polredabs(T, {flag = 0})

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. non-monic polynomials, or pairs `[T, listP]` specifying that a non-maximal 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 use `polredbest` or `polredabs(,16)` to avoid this factorization step; in both cases, the result is 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: Possibly use a suborder of the maximal order, without attempting to certify the result as in Warning 1: we always return a polynomial and never 0. The result is a priori not canonical.

      ? 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) = x^n +...+ 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 x^3-2 rather than x^3+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`: 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.

#### polredbest(T, {flag = 0})

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. non-monic 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 the ring of integers of ℚ[X]/(T), then examines small linear combinations of the basis vectors, computing their characteristic polynomials. It returns the separable P polynomial 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 `Mod(a, 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`⟼` `Mod(a,P)` 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)`.

#### polredord(x)

This function is obsolete, use polredbest.

The library syntax is `GEN polredord(GEN x)`.

#### poltschirnhaus(x)

Applies a random Tschirnhausen transformation to the polynomial x, which is assumed to be non-constant 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)`.

#### rnfalgtobasis(rnf, 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)`.

#### rnfbasis(bnf, M)

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.

The library syntax is `GEN rnfbasis(GEN bnf, GEN M)`.

#### rnfbasistoalg(rnf, x)

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)`.

#### rnfcharpoly(nf, T, a, {var = '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.

#### rnfconductor(bnf, T)

Given a bnf structure attached to a number field K, as produced by `bnfinit`, and T a monic irreducible polynomial in K[x] defining an Abelian extension L = K[x]/(T), computes the class field theory conductor of this Abelian extension. The result is a 3-component vector [conductor,bnr,subgroup], where conductor is the conductor of the extension given as a 2-component row vector [f0,f_ oo ], bnr is the attached `bnr` structure and subgroup is a matrix in HNF defining the subgroup of the ray class group on the ray class group generators `bnr.gen`.

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 prime divisors of rational primes p < B, see `??rnfinit`: the valuation of f0 is then correct at all prime ideals 𝔭 above a rational prime p < B but may be incorrect at other primes.

The library syntax is `GEN rnfconductor(GEN bnf, GEN T)`.

#### rnfdedekind(nf, pol, {pr}, {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 non-zero, 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 non-monic P = ∑i ≤ n ai X^i ∈ ℤK[X] if flag = 1; in this case, we test maximality of Dedekind's order generated by 1, an α, anα^2 + an-1α,..., anαn-1 + an-1αn-2 +...+ a1α. The routine will fail if P is 0 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)`.

#### rnfdet(nf, M)

Given a pseudo-matrix M over the maximal order of nf, computes its determinant.

The library syntax is `GEN rnfdet(GEN nf, GEN M)`.

#### rnfdisc(nf, T)

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 p < B, see `??rnfinit`: the valuation of D is then correct at all prime ideals 𝔭 above a rational prime p < B but may be incorrect at other primes.

The library syntax is `GEN rnfdiscf(GEN nf, GEN T)`.

#### rnfeltabstorel(rnf, x)

Let rnf be a relative number field extension L/K as output by `rnfinit` and let x be an element of L expressed as a polynomial modulo the absolute equation `rnf.pol`, 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.

      ? 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))

The library syntax is `GEN rnfeltabstorel(GEN rnf, GEN x)`.

#### rnfeltdown(rnf, x, {flag = 0})

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.

      ? 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,1,0,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,1,0,0]~) \\ now OK
      %8 = Mod(y, y^2 + 1)

If we had started with `L = rnfinit(K, x^2-y, 1)`, then the final 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).

#### rnfeltnorm(rnf, x)

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
      ? rnfeltnorm(L, Mod(x, x^2-y))

The library syntax is `GEN rnfeltnorm(GEN rnf, GEN x)`.

#### rnfeltreltoabs(rnf, 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.pol`.

      ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y);
      ? L.pol
      %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)

The library syntax is `GEN rnfeltreltoabs(GEN rnf, GEN x)`.

#### rnfelttrace(rnf, 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
      ? rnfelttrace(L, Mod(x, x^2-y))

The library syntax is `GEN rnfelttrace(GEN rnf, GEN x)`.

#### rnfeltup(rnf, x, {flag = 0})

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.

      ? 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]~

The library syntax is `GEN rnfeltup0(GEN rnf, GEN x, long flag)`.

#### rnfequation(nf, pol, {flag = 0})

Given a number field nf as output by `nfinit` (or simply a polynomial) 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 non-zero, 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).

#### rnfhnfbasis(bnf, x)

Given bnf as output by `bnfinit`, and either a polynomial x with coefficients in bnf defining a relative extension L of bnf, or a pseudo-basis x of such an extension, gives either a true bnf-basis of L in upper triangular Hermite normal form, if it exists, and returns 0 otherwise.

The library syntax is `GEN rnfhnfbasis(GEN bnf, GEN x)`.

#### rnfidealabstorel(rnf, x)

Let rnf be a relative number field extension L/K as output by `rnfinit` and x be an ideal of the absolute extension L/ℚ given by a ℤ-basis of elements of 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.

The reason why the input does not use the customary HNF in terms of a fixed ℤ-basis for ℤL is precisely that no such basis has been explicitly specified. On the other hand, if you already computed an (absolute) `nf` structure `Labs` attached to L, and m is in HNF, defining an (absolute) ideal with respect to the ℤ-basis `Labs.zk`, then `Labs.zk * m` is a suitable ℤ-basis for the ideal, and

        rnfidealabstorel(rnf, Labs.zk * m)

converts m to a relative ideal.

      ? K = nfinit(y^2+1); L = rnfinit(K, x^2-y); Labs = nfinit(L);
      ? m = idealhnf(Labs, 17, x^3+2);
      ? B = rnfidealabstorel(L, Labs.zk * m)
      %3 = [[1, 8; 0, 1], [[17, 4; 0, 1], 1]]  \\ pseudo-basis for m as ZK-module
      ? A = rnfidealreltoabs(L, B)
      %4 = [17, x^2 + 4, x + 8, x^3 + 8*x^2]   \\ Z-basis for m in Q[x]/(L.pol)
      ? mathnf(matalgtobasis(Labs, A))
      %5 =
      [17 8 4 2]

      [ 0 1 0 0]

      [ 0 0 1 0]

      [ 0 0 0 1]
      ? % == m
      %6 = 1

The library syntax is `GEN rnfidealabstorel(GEN rnf, GEN x)`.

#### rnfidealdown(rnf, 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)`.

#### rnfidealfactor(rnf, 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)`.

#### rnfidealhnf(rnf, 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)`.

#### rnfidealmul(rnf, x, y)

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)`.

#### rnfidealnormabs(rnf, 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 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)`.

#### rnfidealnormrel(rnf, 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)`.

#### rnfidealprimedec(rnf, pr)

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 prime ideal decomposition of pr in L/K.

      ? K = nfinit(y^2+1); rnf = rnfinit(K, x^3+y+1);
      ? P = idealprimedec(K, 2)[1];
      ? S = rnfidealprimedec(rnf, P);
      ? #S
      %4 = 1

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)`.

#### rnfidealreltoabs(rnf, x, {flag = 0})

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).

#### rnfidealtwoelt(rnf, x)

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)`.

#### rnfidealup(rnf, x, {flag = 0})

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).

#### rnfinit(nf, T, {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] is currently unused.

rnf[6] is currently unused.

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 is an integer. Instead of ℤL, this produces an order which is maximal at all primes less than B. The result is actually a complete and correct rnf structure if all prime divisors of the relative ideal discriminant divide a rational prime less than B. In general, the order may not be maximal at primes 𝔭 | p for p ≥ B 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).

#### rnfisabelian(nf, T)

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)`.

#### rnfisfree(bnf, x)

Given bnf as output by `bnfinit`, and either a polynomial x with coefficients in bnf defining a relative extension L of bnf, or a pseudo-basis x of such an extension, returns true (1) if L/bnf is free, false (0) if not.

The library syntax is `long rnfisfree(GEN bnf, GEN x)`.

#### rnfislocalcyclo(rnf)

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)`.

#### rnfisnorm(T, a, {flag = 0})

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; 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 12log^2|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)`.

#### rnfisnorminit(pol, polrel, {flag = 2})

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)`.

#### rnfkummer(bnr, {subgp}, {d = 0})

bnr being as output by `bnrinit`, finds a relative equation for the class field corresponding to the module in bnr and the given congruence subgroup (the full ray class field if subgp is omitted). If d is positive, outputs the list of all relative equations of degree d contained in the ray class field defined by bnr, with the same conductor as (bnr, subgp).

Warning. This routine only works for subgroups of prime index. It uses Kummer theory, adjoining necessary roots of unity (it needs to compute a tough `bnfinit` here), and finds a generator via Hecke's characterization of ramification in Kummer extensions of prime degree. If your extension does not have prime degree, for the time being, you have to split it by hand as a tower / compositum of such extensions.

The library syntax is `GEN rnfkummer(GEN bnr, GEN subgp = NULL, long d, long prec)`.

#### rnflllgram(nf, pol, order)

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)`.

#### rnfnormgroup(bnr, pol)

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)`.

#### rnfpolred(nf, 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.12.1, 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)`.

#### rnfpolredabs(nf, pol, {flag = 0})

Relative version of `polredabs`. Given an irreducible monic polynomial pol with coefficients in 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: possibly use a suborder of the maximal order. This is slower than the default when the relative discriminant is smooth, and much faster otherwise. In this case the result is no longer canonical; see Section se:polredabs.

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.

The library syntax is `GEN rnfpolredabs(GEN nf, GEN pol, long flag)`.

#### rnfpolredbest(nf, pol, {flag = 0})

Relative version of `polredbest`. Given a monic 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)`.

#### rnfpseudobasis(nf, T)

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 primes p < 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 0]

      [0 3]
      ? [A,J,D,d] = W = rnfpseudobasis(K, [T,100]); D
      time = 5 ms.
      %11 =
      [3 0]

      [0 3]
      ? V == W
      %12 = 1

In this example, the results are identical since D ∩ ℤ factors over primes less than 100. Had it not been the case, the order would have been guaranteed maximal at primes 𝔭 | p for p ≤ 100 only (and might not have been maximal at any maximal ideal 𝔭 such that 𝔭^2 dividing D.

The library syntax is `GEN rnfpseudobasis(GEN nf, GEN T)`.

#### rnfsteinitz(nf, x)

Given a number field nf as output by `nfinit` and either a polynomial x with coefficients in nf defining a relative extension L of nf, or a pseudo-basis x of such an extension as output for example by `rnfpseudobasis`, computes another 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, and outputs the four-component row vector [A,I,D,d] as in `rnfpseudobasis`. The name of this function comes from the fact that the ideal class of the last ideal of I, which is well defined, is the Steinitz class of the ℤK-module ℤL (its image in SK0(ℤK)).

The library syntax is `GEN rnfsteinitz(GEN nf, GEN x)`.

#### subgrouplist(bnr, {bound}, {flag = 0})

bnr being as output by `bnrinit` or a list of cyclic components of a finite Abelian group G, 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 bnr is as output by `bnrinit`, gives only the subgroups whose modulus is the conductor. Otherwise, the modulus is not taken into account.

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 `rnfkummer`.)

The library syntax is `GEN subgrouplist0(GEN bnr, GEN bound = NULL, long flag)`.