# NAME

libPARI - Technical Reference Guide: the basics

In the following chapters, we describe all public low-level functions of the PARI library. These include specialized functions for handling all the PARI types. Simple higher level functions, such as arithmetic or transcendental functions, are described in Chapter 3 of the GP user's manual; we will eventually see more general or flexible versions in the chapters to come. A general introduction to the major concepts of PARI programming can be found in Chapter 4, which you should really read first.

We shall now study specialized functions, more efficient than the library wrappers, but sloppier on argument checking and damage control; besides speed, their main advantage is to give finer control about the inner workings of generic routines, offering more options to the programmer.

@3Important advice. Generic routines eventually call lower level functions. Optimize your algorithms first, not overhead and conversion costs between PARI routines. For generic operations, use generic routines first; do not waste time looking for the most specialized one available unless you identify a genuine bottleneck, or you need some special behavior the generic routine does not offer. The PARI source code is part of the documentation; look for inspiration there.

The type long denotes a BITS_IN_LONG-bit signed long integer (32 or 64 bits). The type ulong is defined as unsigned long. The word stack always refer to the PARI stack, allocated through an initial pari_init call. Refer to Chapters 1--2 and 4 for general background.

We shall often refer to the notion of shallow function, which means that some components of the result may point to components of the input, which is more efficient than a deep copy (full recursive copy of the object tree). Such outputs are not suitable for gerepileupto and particular care must be taken when garbage collecting objects which have been input to shallow functions: corresponding outputs also become invalid and should no longer be accessed.

A function is not stack clean if it leaves intermediate data on the stack besides its output, for efficiency reasons.

# Initializing the library

The following functions enable you to start using the PARI functions in a program, and cleanup without exiting the whole program.

## General purpose

void pari_init(size_t size, ulong maxprime) initialize the library, with a stack of size bytes and a prime table up to the maximum of maxprime and 2^{16}. Unless otherwise mentioned, no PARI function will function properly before such an initialization.

void pari_close(void) stop using the library (assuming it was initialized with pari_init) and frees all allocated objects.

## Technical functions

void pari_init_opts(size_t size, ulong maxprime, ulong opts) as pari_init, more flexible. opts is a mask of flags among the following:

INIT_JMPm: install PARI error handler. When an exception is raised, the program is terminated with exit(1).

INIT_SIGm: install PARI signal handler.

INIT_DFTm: initialize the GP_DATA environment structure. This one must be enabled once. If you close pari, then restart it, you need not reinitialize GP_DATA; if you do not, then old values are restored.

INIT_noPRIMEm: do not compute the prime table (ignore the maxprime argument). The user must call pari_init_primes later.

INIT_noIMTm: (technical, see pari_mt_init in the Developer's Guide for detail). Do not call pari_mt_init to initialize the multi-thread engine. If this flag is set, pari_mt_init() will need to be called manually. See examples/pari-mt.c for an example.

INIT_noINTGMPm: do not install PARI-specific GMP memory functions. This option is ignored when the GMP library is not in use. You may install PARI-specific GMP memory functions later by calling

void pari_kernel_init(void)

@3and restore the previous values using

void pari_kernel_close(void)

This option should not be used without a thorough understanding of the problem you are trying to solve. The GMP memory functions are global variables used by the GMP library. If your program is linked with two libraries that require these variables to be set to different values, conflict ensues. To avoid a conflict, the proper solution is to record their values with mp_get_memory_functions and to call mp_set_memory_functions to restore the expected values each time the code switches from using one library to the other. Here is an example:

  void *(*pari_alloc_ptr) (size_t);
void *(*pari_realloc_ptr) (void *, size_t, size_t);
void (*pari_free_ptr) (void *, size_t);
void *(*otherlib_alloc_ptr) (size_t);
void *(*otherlib_realloc_ptr) (void *, size_t, size_t);
void (*otherlib_free_ptr) (void *, size_t);

void init(void)
{
pari_init(8000000, 500000);
mp_get_memory_functions(&pari_alloc_ptr,&pari_realloc_ptr,
&pari_free_ptr);
otherlib_init();
mp_get_memory_functions(&otherlib_alloc_ptr,&otherlib_realloc_ptr,
&otherlib_free_ptr);
}
void function_that_use_pari(void)
{
mp_set_memory_functions(pari_alloc_ptr,pari_realloc_ptr,
pari_free_ptr);
/*use PARI functions*/
}
void function_that_use_otherlib(void)
{
mp_set_memory_functions(otherlib_alloc_ptr,otherlib_realloc_ptr,
otherlib_free_ptr);
/*use OTHERLIB functions*/
}

void pari_close_opts(ulong init_opts) as pari_close, for a library initialized with a mask of options using pari_init_opts. opts is a mask of flags among

INIT_SIGm: restore SIG_DFL default action for signals tampered with by PARI signal handler.

INIT_DFTm: frees the GP_DATA environment structure.

INIT_noIMTm: (technical, see pari_mt_init in the Developer's Guide for detail). Do not call pari_mt_close to close the multi-thread engine. INIT_noINTGMPm: do not restore GMP memory functions.

void pari_sig_init(void (*f)(int)) install the signal handler f (see signal(2)): the signals SIGBUS, SIGFPE, SIGINT, SIGBREAK, SIGPIPE and SIGSEGV are concerned.

void pari_init_primes(ulong maxprime) Initialize the PARI primes. This function is called by pari_init(...,maxprime). It is provided for users calling pari_init_opts with the flag INIT_noPRIMEm.

void pari_sighandler(int signum) the actual signal handler that PARI uses. This can be used as argument to pari_sig_init or signal(2).

void pari_stackcheck_init(void *stackbase) controls the system stack exhaustion checking code in the GP interpreter. This should be used when the system stack base address change or when the address seen by pari_init is too far from the base address. If stackbase is NULL, disable the check, else set the base address to stackbase. It is normally used this way

  int thread_start (...)
{
long first_item_on_the_stack;
...
pari_stackcheck_init(&first_item_on_the_stack);
}

int pari_daemon(void) forks a PARI daemon, detaching from the main process group. The function returns 1 in the parent, and 0 in the forked son.

void paristack_setsize(size_t rsize, size_t vsize) sets the default parisize to rsize and the default parisizemax to vsize, and reallocate the stack to match these value, destroying its content. Generally used just after pari_init.

void paristack_resize(ulong newsize) changes the current stack size to newsize (double it if newsize is 0). The new size is clipped to be at least the current stack size and at most parisizemax. The stack content is not affected by this operation.

void parivstack_reset(void) resets the current stack to its default size parisize, destroying its content. Used to recover memory after a computation that enlarged the stack.

void paristack_newrsize(ulong newsize) (does not return). Library version of

    default(parisize, "newsize")

@3Set the default parisize to newsize, or double parisize if newsize is equal to 0, then call cb_pari_err_recover(-1).

void parivstack_resize(ulong newsize) (does not return). Library version of

    default(parisizemax, "newsize")

@3Set the default parisizemax to newsize and call cb_pari_err_recover(-1).

## Notions specific to the GP interpreter

An entree is the generic object attached to an identifier (a name) in GP's interpreter, be it a built-in or user function, or a variable. For a function, it has at least the following fields:

char *name: the name under which the interpreter knows us.

void *value: a pointer to the C function to call.

long menu: a small integer  >= 1 (to which group of function help do we belong, for the ?n help menu).

char *code: the prototype code.

char *help: the help text for the function.

A routine in GP is described to the analyzer by an entree structure. Built-in PARI routines are grouped in modules, which are arrays of entree structs, the last of which satisfy name = NULL (sentinel). There are currently five modules in PARI/GP:

@3* general functions (functions_basic, known to libpari),

@3* gp-specific functions (functions_gp),

@3* gp-specific highlevel functions (functions_highlevel),

@3and two modules of obsolete functions. The function pari_init initializes the interpreter and declares all symbols in functions_basic. You may declare further functions on a case by case basis or as a whole module using

void pari_add_function(entree *ep) adds a single routine to the table of symbols in the interpreter. It assumes pari_init has been called.

void pari_add_module(entree *mod) adds all the routines in module mod to the table of symbols in the interpreter. It assumes pari_init has been called.

@3For instance, gp implements a number of private routines, which it adds to the default set via the calls

    pari_add_module(functions_gp);
pari_add_module(functions_highlevel);

A GP default is likewise attached to a helper routine, that is run when the value is consulted, or changed by default0 or setdefault. Such routines are grouped in the module functions_default.

void pari_add_defaults_module(entree *mod) adds all the defaults in module mod to the interpreter. It assumes that pari_init has been called. From this point on, all defaults in module mod are known to setdefault and friends.

## Public callbacks

The gp calculator associates elaborate functions (for instance the break loop handler) to the following callbacks, and so can you:

\doc{cb_pari_ask_confirm}{void (*cb_pari_ask_confirm)(const char *s)} initialized to NULL. Called with argument s whenever PARI wants confirmation for action s, for instance in secure mode.

\doc{cb_pari_init_histfile}{void (*cb_pari_init_histfile)(void)} initialized to NULL. Called when the histfile default is changed. The intent is for that callback to read the file content, append it to history in memory, then dump the expanded history to the new histfile.

\doc{cb_pari_is_interactive}{int (*cb_pari_is_interactive)(void)}; initialized to NULL.

\doc{cb_pari_quit}{void (*cb_pari_quit)(long)} initialized to a no-op. Called when gp must evaluate the quit command.

\doc{cb_pari_start_output}{void (*cb_pari_start_output)(void)} initialized to NULL.

\doc{cb_pari_handle_exception}{int (*cb_pari_handle_exception)(long)} initialized to NULL. If not NULL, this routine is called with argument -1 on SIGINT, and argument err on error err. If it returns a non-zero value, the error or signal handler returns, in effect further ignoring the error or signal, otherwise it raises a fatal error. A possible simple-minded handler, used by the gp interpreter, is

int gp_handle_exception(long err) if the breakloop default is enabled (set to 1) and cb_pari_break_loop is not NULL, we call this routine with err argument and return the result.

\doc{cb_pari_err_handle}{int (*cb_pari_err_handle)(GEN)} If not NULL, this routine is called with a t_ERROR argument from pari_err. If it returns a non-zero value, the error returns, in effect further ignoring the error, otherwise it raises a fatal error.

The default behaviour is to print a descriptive error message (display the error), then return 0, thereby raising a fatal error. This differs from cb_pari_handle_exception in that the function is not called on SIGINT (which do not generate a t_ERROR), only from pari_err. Use cb_pari_sigint if you need to handle SIGINT as well.

\doc{cb_pari_break_loop}{int (*cb_pari_break_loop)(int)} initialized to NULL.

\doc{cb_pari_sigint}{void (*cb_pari_sigint)(void)}. Function called when we receive SIGINT. By default, raises

    pari_err(e_MISC, "user interrupt");

@3A possible simple-minded variant, used by the gp interpreter, is

void gp_sigint_fun(void)

\doc{cb_pari_pre_recover}{void (*cb_pari_err_recover)(long)} initialized to NULL. If not NULL, this routine is called just before PARI cleans up from an error. It is not required to return. The error number is passed as argument, unless the PARI stack has been destroyed (allocatemem), in which case -1 is passed.

\doc{cb_pari_err_recover}{void (*cb_pari_err_recover)(long)} initialized to pari_exit(). This callback must not return. It is called after PARI has cleaned-up from an error. The error number is passed as argument, unless the PARI stack has been destroyed, in which case it is called with argument -1.

\doc{cb_pari_whatnow}{int (*cb_pari_whatnow)(PariOUT *out, const char *s, int flag)} initialized to NULL. If not NULL, must check whether s existed in older versions of pari (the gp callback checks against pari-1.39.15). All output must be done via out methods.

@3* flag = 0: should print verbosely the answer, including help text if available.

@3* flag = 1: must return 0 if the function did not change, and a non-0 result otherwise. May print a help message.

## Configuration variables

pari_library_path: If set, It should be a path to the libpari library. It is used by the function gpinstall to locate the PARI library when searching for symbols. This should only be useful on Windows.

## Utility functions

void pari_ask_confirm(const char *s) raise an error if the callback cb_pari_ask_confirm is NULL. Otherwise calls

    cb_pari_ask_confirm(s);

char* gp_filter(const char *s) pre-processor for the GP parser: filter out whitespace and GP comments from s.

GEN pari_compile_str(const char *s) low-level form of compile_str: assumes that s does not contain spaces or GP comments and returns the closure attached to the GP expression s. Note that GP metacommands are not recognized.

int gp_meta(const char *s, int ismain) low-level component of gp_read_str: assumes that s does not contain spaces or GP comments and try to interpret s as a GP metacommand (e.g. starting by \ or ?). If successful, execute the metacommand and return 1; otherwise return 0. The ismain parameter modifies the way \r commands are handled: if non-zero, act as if the file contents were entered via standard input (i.e. call switchin and divert pari_infile); otherwise, simply call gp_read_file.

void pari_hit_return(void) wait for the use to enter \n via standard input.

void gp_load_gprc(void) read and execute the user's GPRC file.

void pari_center(const char *s) print s, centered.

void pari_print_version(void) print verbose version information.

const char* gp_format_time(long t) format a delay of t ms suitable for gp output, with timer set.

const char* gp_format_prompt(const char *p) format a prompt p suitable for gp prompting (includes colors and protecting ANSI escape sequences for readline).

void pari_alarm(long s) set an alarm after s seconds (raise an e_ALARM exception).

void gp_help(const char *s, long flag) print help for s, depending on the value of flag:

@3* h_REGULAR, basic help (?);

@3* h_LONG, extended help (??);

@3* h_APROPOS, a propos help (??).

const char ** gphelp_keyword_list(void) return a NULL-terminated array a strings, containing keywords known to gphelp besides GP functions (e.g. modulus or operator). Used by the online help system and the contextual completion engine.

void gp_echo_and_log(const char *p, const char *s) given a prompt p and attached input command s, update logfile and possibly print on standard output if echo is set and we are not in interactive mode. The callback cb_pari_is_interactive must be set to a sensible value.

void gp_alarm_handler(int sig) the SIGALRM handler set by the gp interpreter.

void print_fun_list(char **list, long n) print all elements of list in columns, pausing (hit return) every n lines. list is NULL terminated.

## Saving and restoring the GP context

void gp_context_save(struct gp_context* rec) save the current GP context.

void gp_context_restore(struct gp_context* rec) restore a GP context. The new context must be an ancestor of the current context.

## GP history

These functions allow to control the GP history (the % operator).

void pari_add_hist(GEN x, long t) adds x as the last history entry; t is the time we used to compute it.

GEN pari_get_hist(long p), if p > 0 returns entry of index p (i.e. %p), else returns entry of index n+p where n is the index of the last entry (used for %, %, %, etc.).

long pari_get_histtime(long p) as pari_get_hist, returning the time used to compute the history entry, instead of the entry itself.

ulong pari_nb_hist(void) return the index of the last entry.

# Handling GENs

@3Almost all these functions are either macros or inlined. Unless mentioned otherwise, they do not evaluate their arguments twice. Most of them are specific to a set of types, although no consistency checks are made: e.g. one may access the sign of a t_PADIC, but the result is meaningless.

## Allocation

GEN cgetg(long l, long t) allocates (the root of) a GEN of type t and length l. Sets z[0].

GEN cgeti(long l) allocates a t_INT of length l (including the 2 codewords). Sets z[0] only.

GEN cgetr(long l) allocates a t_REAL of length l (including the 2 codewords). Sets z[0] only.

GEN cgetc(long prec) allocates a t_COMPLEX whose real and imaginary parts are t_REALs of length prec.

GEN cgetg_copy(GEN x, long *lx) fast version of cgetg: allocate a GEN with the same type and length as x, setting *lx to lg(x) as a side-effect. (Only sets the first codeword.) This is a little faster than cgetg since we may reuse the bitmask in x[0] instead of recomputing it, and we do not need to check that the length does not overflow the possibilities of the implementation (since an object with that length already exists). Note that cgetg with arguments known at compile time, as in

    cgetg(3, t_INTMOD)

@3will be even faster since the compiler will directly perform all computations and checks.

GEN vectrunc_init(long l) perform cgetg(l,t_VEC), then set the length to 1 and return the result. This is used to implement vectors whose final length is easily bounded at creation time, that we intend to fill gradually using:

void vectrunc_append(GEN x, GEN y) assuming x was allocated using vectrunc_init, appends y as the last element of x, which grows in the process. The function is shallow: we append y, not a copy; it is equivalent to

    long lx = lg(x); gel(x,lx) = y; setlg(x, lx+1);

Beware that the maximal size of x (the l argument to vectrunc_init) is unknown, hence unchecked, and stack corruption will occur if we append more than l-1 elements to x. Use the safer (but slower) shallowconcat when l is not easy to bound in advance.

An other possibility is simply to allocate using cgetg(l, t) then fill the components as they become available: this time the downside is that we do not obtain a correct GEN until the vector is complete. Almost no PARI function will be able to operate on it.

void vectrunc_append_batch(GEN x, GEN y) successively apply

    vectrunc_append(x, gel(y, i))

for all elements of the vector y.

GEN vecsmalltrunc_init(long l)

void vecsmalltrunc_append(GEN x, long t) analog to the above for a t_VECSMALL container.

## Length conversions

These routines convert a non-negative length to different units. Their behavior is undefined at negative integers.

long ndec2nlong(long x) converts a number of decimal digits to a number of words. Returns  1 + floor(x x BIL  log _2 10).

long ndec2prec(long x) converts a number of decimal digits to a number of codewords. This is equal to 2 + ndec2nlong(x).

long ndec2nbits(long x) convers a number of decimal digits to a number of bits.

long prec2ndec(long x) converts a number of codewords to a number of decimal digits.

long nbits2nlong(long x) converts a number of bits to a number of words. Returns the smallest word count containing x bits, i.e  ceil(x / BIL).

long nbits2ndec(long x) converts a number of bits to a number of decimal digits.

long nbits2lg(long x) converts a number of bits to a length in code words. Currently an alias for nbits2nlong.

long nbits2prec(long x) converts a number of bits to a number of codewords. This is equal to 2 + nbits2nlong(x).

long nbits2extraprec(long x) converts a number of bits to the mantissa length of a t_REAL in codewords. This is currently an alias to nbits2nlong(x).

long nchar2nlong(long x) converts a number of bytes to number of words. Returns the smallest word count containing x bytes, i.e ceil(x / sizeof(long)).

long prec2nbits(long x) converts a t_REAL length into a number of significant bits; returns (x - 2)BIL.

double prec2nbits_mul(long x, double y) returns prec2nbits(x) x y.

long bit_accuracy(long x) converts a length into a number of significant bits; currently an alias for prec2nbits.

double bit_accuracy_mul(long x, double y) returns bit_accuracy(x) x y.

long realprec(GEN x) length of a t_REAL in words; currently an alias for lg.

long bit_prec(GEN x) length of a t_REAL in bits.

long precdbl(long prec) given a length in words corresponding to a t_REAL precision, return the length corresponding to doubling the precision. Due to the presence of 2 code words, this is 2(prec - 2) + 2.

long typ(GEN x) returns the type number of x. The header files included through pari.h define symbolic constants for the GEN types: t_INT etc. Never use their actual numerical values. E.g to determine whether x is a t_INT, simply check

    if (typ(x) == t_INT) { }

The types are internally ordered and this simplifies the implementation of commutative binary operations (e.g addition, gcd). Avoid using the ordering directly, as it may change in the future; use type grouping functions instead ("Label se:typegroup").

const char* type_name(long t) given a type number t this routine returns a string containing its symbolic name. E.g type_name(t_INT) returns "t_INT". The return value is read-only.

long lg(GEN x) returns the length of x in BIL-bit words.

long lgefint(GEN x) returns the effective length of the t_INT x in BIL-bit words.

long signe(GEN x) returns the sign (-1, 0 or 1) of x. Can be used for t_INT, t_REAL, t_POL and t_SER (for the last two types, only 0 or 1 are possible).

long gsigne(GEN x) returns the sign of a real number x, valid for t_INT, t_REAL as signe, but also for t_FRAC and t_QUAD of positive discriminants. Raise a type error if typ(x) is not among those.

long expi(GEN x) returns the binary exponent of the real number equal to the t_INT x. This is a special case of gexpo.

long expo(GEN x) returns the binary exponent of the t_REAL x.

long mpexpo(GEN x) returns the binary exponent of the t_INT or t_REAL x.

long gexpo(GEN x) same as expo, but also valid when x is not a t_REAL (returns the largest exponent found among the components of x). When x is an exact 0, this returns -HIGHEXPOBIT, which is lower than any valid exponent.

long valp(GEN x) returns the p-adic valuation (for a t_PADIC) or X-adic valuation (for a t_SER, taken with respect to the main variable) of x.

long precp(GEN x) returns the precision of the t_PADIC x.

long varn(GEN x) returns the variable number of the t_POL or t_SER x (between 0 and MAXVARN).

long gvar(GEN x) returns the main variable number when any variable at all occurs in the composite object x (the smallest variable number which occurs), and NO_VARIABLE otherwise.

long gvar2(GEN x) returns the variable number for the ring over which x is defined, e.g. if x\in Z[a][b] return (the variable number for) a. Return NO_VARIABLE if x has no variable or is not defined over a polynomial ring.

long degpol(GEN x) is a simple macro returning lg(x) - 3. This is the degree of the t_POL x with respect to its main variable, if its leading coefficient is non-zero (a rational 0 is impossible, but an inexact 0 is allowed, as well as an exact modular 0, e.g. Mod(0,2)). If x has no coefficients (rational 0 polynomial), its length is 2 and we return the expected -1.

long lgpol(GEN x) is equal to degpol(x) + 1. Used to loop over the coefficients of a t_POL in the following situation:

      GEN xd = x + 2;
long i, l = lgpol(x);
for (i = 0; i < l; i++) foo( xd[i] ).

long precision(GEN x) If x is of type t_REAL, returns the precision of x, namely the length of x in BIL-bit words if x is not zero, and a reasonable quantity obtained from the exponent of x if x is numerically equal to zero. If x is of type t_COMPLEX, returns the minimum of the precisions of the real and imaginary part. Otherwise, returns 0 (which stands for infinite precision).

long lgcols(GEN x) is equal to lg(gel(x,1)). This is the length of the columns of a t_MAT with at least one column.

long nbrows(GEN x) is equal to lg(gel(x,1))-1. This is the number of rows of a t_MAT with at least one column.

long gprecision(GEN x) as precision for scalars. Returns the lowest precision encountered among the components otherwise.

long sizedigit(GEN x) returns 0 if x is exactly 0. Otherwise, returns gexpo(x) multiplied by log _{10}(2). This gives a crude estimate for the maximal number of decimal digits of the components of x.

## Eval type-dependent information

These routines convert type-dependent information to bitmask to fill the codewords of GEN objects (see "Label se:impl"). E.g for a t_REAL z:

    z[1] = evalsigne(-1) | evalexpo(2)

Compatible components of a codeword for a given type can be OR-ed as above.

ulong evaltyp(long x) convert type x to bitmask (first codeword of all GENs)

long evallg(long x) convert length x to bitmask (first codeword of all GENs). Raise overflow error if x is so large that the corresponding length cannot be represented

long _evallg(long x) as evallg without the overflow check.

ulong evalvarn(long x) convert variable number x to bitmask (second codeword of t_POL and t_SER)

long evalsigne(long x) convert sign x (in -1,0,1) to bitmask (second codeword of t_INT, t_REAL, t_POL, t_SER)

long evalprecp(long x) convert p-adic (X-adic) precision x to bitmask (second codeword of t_PADIC, t_SER). Raise overflow error if x is so large that the corresponding precision cannot be represented.

long _evalprecp(long x) same as evalprecp without the overflow check.

long evalvalp(long x) convert p-adic (X-adic) valuation x to bitmask (second codeword of t_PADIC, t_SER). Raise overflow error if x is so large that the corresponding valuation cannot be represented.

long _evalvalp(long x) same as evalvalp without the overflow check.

long evalexpo(long x) convert exponent x to bitmask (second codeword of t_REAL). Raise overflow error if x is so large that the corresponding exponent cannot be represented

long _evalexpo(long x) same as evalexpo without the overflow check.

long evallgefint(long x) convert effective length x to bitmask (second codeword t_INT). This should be less or equal than the length of the t_INT, hence there is no overflow check for the effective length.

## Set type-dependent information

Use these functions and macros with extreme care since usually the corresponding information is set otherwise, and the components and further codeword fields (which are left unchanged) may not be compatible with the new information.

void settyp(GEN x, long s) sets the type number of x to s.

void setlg(GEN x, long s) sets the length of x to s. This is an efficient way of truncating vectors, matrices or polynomials.

void setlgefint(GEN x, long s) sets the effective length of the t_INT x to s. The number s must be less than or equal to the length of x.

void setsigne(GEN x, long s) sets the sign of x to s. If x is a t_INT or t_REAL, s must be equal to -1, 0 or 1, and if x is a t_POL or t_SER, s must be equal to 0 or 1. No sanity check is made; in particular, setting the sign of a 0 t_INT to +-1 creates an invalid object.

void togglesign(GEN x) sets the sign s of x to -s, in place.

void togglesign_safe(GEN *x) sets the s sign of *x to -s, in place, unless *x is one of the integer universal constants in which case replace *x by its negation (e.g. replace gen_1 by gen_m1).

void setabssign(GEN x) sets the sign s of x to |s|, in place.

void affectsign(GEN x, GEN y) shortcut for setsigne(y, signe(x)). No sanity check is made; in particular, setting the sign of a 0 t_INT to +-1 creates an invalid object.

void affectsign_safe(GEN x, GEN *y) sets the sign of *y to that of x, in place, unless *y is one of the integer universal constants in which case replace *y by its negation if needed (e.g. replace gen_1 by gen_m1 if x is negative). No other sanity check is made; in particular, setting the sign of a 0 t_INT to +-1 creates an invalid object.

void normalize_frac(GEN z) assuming z is of the form mkfrac(a,b) with b != 0, make sure that b > 0 by changing the sign of a in place if needed (use togglesign).

void setexpo(GEN x, long s) sets the binary exponent of the t_REAL x to s. The value s must be a 24-bit signed number.

void setvalp(GEN x, long s) sets the p-adic or X-adic valuation of x to s, if x is a t_PADIC or a t_SER, respectively.

void setprecp(GEN x, long s) sets the p-adic precision of the t_PADIC x to s.

void setvarn(GEN x, long s) sets the variable number of the t_POL or t_SER x to s (where 0 <= s <= MAXVARN).

## Type groups

In the following functions, t denotes the type of a GEN. They used to be implemented as macros, which could evaluate their argument twice; no longer: it is not inefficient to write

    is_intreal_t(typ(x))

int is_recursive_t(long t) true iff t is a recursive type (the non-recursive types are t_INT, t_REAL, t_STR, t_VECSMALL). Somewhat contrary to intuition, t_LIST is also non-recursive, ; see the Developer's guide for details.

int is_intreal_t(long t) true iff t is t_INT or t_REAL.

int is_rational_t(long t) true iff t is t_INT or t_FRAC.

int is_real_t(long t) true iff t is t_INT or t_REAL or t_FRAC.

int is_vec_t(long t) true iff t is t_VEC or t_COL.

int is_matvec_t(long t) true iff t is t_MAT, t_VEC or t_COL.

int is_scalar_t(long t) true iff t is a scalar, i.e a t_INT, a t_REAL, a t_INTMOD, a t_FRAC, a t_COMPLEX, a t_PADIC, a t_QUAD, or a t_POLMOD.

int is_extscalar_t(long t) true iff t is a scalar (see is_scalar_t) or t is t_POL.

int is_const_t(long t) true iff t is a scalar which is not t_POLMOD.

int is_noncalc_t(long t) true if generic operations (gadd, gmul) do not make sense for t: corresponds to types t_LIST, t_STR, t_VECSMALL, t_CLOSURE

## Accessors and components

The first two functions return GEN components as copies on the stack:

GEN compo(GEN x, long n) creates a copy of the n-th true component (i.e. not counting the codewords) of the object x.

GEN truecoeff(GEN x, long n) creates a copy of the coefficient of degree n of x if x is a scalar, t_POL or t_SER, and otherwise of the n-th component of x.

@3On the contrary, the following routines return the address of a GEN component. No copy is made on the stack:

GEN constant_coeff(GEN x) returns the address of the constant coefficient of t_POL x. By convention, a 0 polynomial (whose sign is 0) has gen_0 constant term.

GEN leading_coeff(GEN x) returns the address of the leading coefficient of t_POL x, i.e. the coefficient of largest index stored in the array representing x. This may be an inexact 0. By convention, return gen_0 if the coefficient array is empty.

GEN gel(GEN x, long i) returns the address of the x[i] entry of x. (el stands for element.)

GEN gcoeff(GEN x, long i, long j) returns the address of the x[i,j] entry of t_MAT x, i.e. the coefficient at row i and column j.

GEN gmael(GEN x, long i, long j) returns the address of the x[i][j] entry of x. (mael stands for multidimensional array element.)

GEN gmael2(GEN A, long x1, long x2) is an alias for gmael. Similar macros gmael3, gmael4, gmael5 are available.

# Global numerical constants

These are defined in the various public PARI headers.

@3long BITS_IN_LONG = 2^{TWOPOTBITS_IN_LONG}: number of bits in a long (32 or 64).

@3long BITS_IN_HALFULONG: BITS_IN_LONG divided by 2.

@3long LONG_MAX: the largest positive long.

@3ulong ULONG_MAX: the largest ulong.

@3long DEFAULTPREC: the length (lg) of a t_REAL with 64 bits of accuracy

@3long MEDDEFAULTPREC: the length (lg) of a t_REAL with 128 bits of accuracy

@3long BIGDEFAULTPREC: the length (lg) of a t_REAL with 192 bits of accuracy

@3ulong HIGHBIT: the largest power of 2 fitting in an ulong.

@3ulong LOWMASK: bitmask yielding the least significant bits.

@3ulong HIGHMASK: bitmask yielding the most significant bits.

@3The last two are used to implement the following convenience macros, returning half the bits of their operand:

ulong LOWWORD(ulong a) returns least significant bits.

ulong HIGHWORD(ulong a) returns most significant bits.

@3Finally

long divsBIL(long n) returns the Euclidean quotient of n by BITS_IN_LONG (with non-negative remainder).

long remsBIL(n) returns the (non-negative) Euclidean remainder of n by BITS_IN_LONG

long dvmdsBIL(long n, long *r)

ulong dvmduBIL(ulong n, ulong *r) sets r to remsBIL(n) and returns divsBIL(n).

## Masks used to implement the GEN type

These constants are used by higher level macros, like typ or lg:

@3EXPOnumBITS, LGnumBITS, SIGNnumBITS, TYPnumBITS, VALPnumBITS, VARNnumBITS: number of bits used to encode expo, lg, signe, typ, valp, varn.

@3PRECPSHIFT, SIGNSHIFT, TYPSHIFT, VARNSHIFT: shifts used to recover or encode precp, varn, typ, signe

@3CLONEBIT, EXPOBITS, LGBITS, PRECPBITS, SIGNBITS, TYPBITS, VALPBITS, VARNBITS: bitmasks used to extract isclone, expo, lg, precp, signe, typ, valp, varn from GEN codewords.

@3MAXVARN: the largest possible variable number.

@3NO_VARIABLE: sentinel returned by gvar(x) when x does not contain any polynomial; has a lower priority than any valid variable number.

@3HIGHEXPOBIT: a power of 2, one more that the largest possible exponent for a t_REAL.

@3HIGHVALPBIT: a power of 2, one more that the largest possible valuation for a t_PADIC or a t_SER.

## log 2, pi

These are double approximations to useful constants:

@3LOG2: log  2.

@3LOG10_2: log  2 /  log  10.

@3LOG2_10: log  10 /  log  2.

@3M_PI: pi.

# Iterating over small primes, low-level interface

One of the methods used by the high-level prime iterator (see "Label se:primeiter"), is a precomputed table. Its direct use is deprecated, but documented here.

After pari_init(size, maxprime), a prime table'' is initialized with the successive differences of primes up to (possibly just a little beyond) maxprime. The prime table occupies roughly maxprime/ log (maxprime) bytes in memory, so be sensible when choosing maxprime; it is 500000 by default under gp and there is no real benefit in choosing a much larger value: the high-level iterator provide fast access to primes up to the square of maxprime. In any case, the implementation requires that maxprime < 2^{BIL} - 2048, whatever memory is available.

PARI currently guarantees that the first 6547 primes, up to and including 65557, are present in the table, even if you set maxprime to zero. in the pari_init call.

@3Some convenience functions:

ulong maxprime() the largest prime computable using our prime table.

void maxprime_check(ulong B) raise an error if maxprime() is  < B.

After the following initializations (the names p and ptr are arbitrary of course)

  byteptr ptr = diffptr;
ulong p = 0;

@3calling the macro NEXT_PRIME_VIADIFF_CHECK(p, ptr) repeatedly will assign the successive prime numbers to p. Overrunning the prime table boundary will raise the error e_MAXPRIME, which just prints the error message:

*** not enough precomputed primes, need primelimit ~ c

@3(for some numerical value c), then the macro aborts the computation. The alternative macro NEXT_PRIME_VIADIFF operates in the same way, but will omit that check, and is slightly faster. It should be used in the following way:

  byteptr ptr = diffptr;
ulong p = 0;

if (maxprime() < goal) pari_err_MAXPRIME(goal); /* not enough primes */
while (p <= goal) /* run through all primes up to C<goal> */
{
...
}

@3 Here, we use the general error handling function pari_err (see "Label se:err"), with the codeword e_MAXPRIME, raising the not enough primes'' error. This could be rewritten as

  maxprime_check(goal);
while (p <= goal) /* run through all primes up to C<goal> */
{
...
}

bytepr initprimes(ulong maxprime, long *L, ulong *lastp) computes a (malloc'ed) prime table'', in fact a table of all prime differences for p < maxprime (and possibly a little beyond). Set L to the table length (argument to malloc), and lastp to the last prime in the table.

void initprimetable(ulong maxprime) computes a prime table (of all prime differences for p < maxprime) and assign it to the global variable diffptr. Don't change diffptr directly, call this function instead. This calls initprimes and updates internal data recording the table size.

ulong init_primepointer_geq(ulong a, byteptr *pd) returns the smallest prime p >= a, and sets *pd to the proper offset of diffptr so that NEXT_PRIME_VIADIFF(p, *pd) correctly returns unextprime(p + 1).

ulong init_primepointer_gt(ulong a, byteptr *pd) returns the smallest prime p > a.

ulong init_primepointer_leq(ulong a, byteptr *pd) returns the largest prime p <= a.

ulong init_primepointer_lt(ulong a, byteptr *pd) returns the largest prime p < a.

# Handling the PARI stack

## Allocating memory on the stack

GEN cgetg(long n, long t) allocates memory on the stack for an object of length n and type t, and initializes its first codeword.

GEN cgeti(long n) allocates memory on the stack for a t_INT of length n, and initializes its first codeword. Identical to cgetg(n,t_INT).

GEN cgetr(long n) allocates memory on the stack for a t_REAL of length n, and initializes its first codeword. Identical to cgetg(n,t_REAL).

GEN cgetc(long n) allocates memory on the stack for a t_COMPLEX, whose real and imaginary parts are t_REALs of length n.

GEN cgetp(GEN x) creates space sufficient to hold the t_PADIC x, and sets the prime p and the p-adic precision to those of x, but does not copy (the p-adic unit or zero representative and the modulus of) x.

GEN new_chunk(size_t n) allocates a GEN with n components, without filling the required code words. This is the low-level constructor underlying cgetg, which calls new_chunk then sets the first code word. It works by simply returning the address ((GEN)avma) - n, after checking that it is larger than (GEN)bot.

void new_chunk_resize(size_t x) this function is called by new_chunk when the PARI stack overflows. There is no need to call it manually. It will either extend the stack or report an e_STACK error.

char* stack_malloc(size_t n) allocates memory on the stack for n chars (not n GENs). This is faster than using malloc, and easier to use in most situations when temporary storage is needed. In particular there is no need to free individually all variables thus allocated: a simple avma = oldavma might be enough. On the other hand, beware that this is not permanent independent storage, but part of the stack.

char* stack_calloc(size_t n) as stack_malloc, setting the memory to zero.

@3Objects allocated through these last three functions cannot be gerepile'd, since they are not yet valid GENs: their codewords must be filled first.

GEN cgetalloc(long t, size_t l), same as cgetg(t, l), except that the result is allocated using pari_malloc instead of the PARI stack. The resulting GEN is now impervious to garbage collecting routines, but should be freed using pari_free.

## Stack-independent binary objects

GENbin* copy_bin(GEN x) copies x into a malloc'ed structure suitable for stack-independent binary transmission or storage. The object obtained is architecture independent provided, sizeof(long) remains the same on all PARI instances involved, as well as the multiprecision kernel (either native or GMP).

GENbin* copy_bin_canon(GEN x) as copy_bin, ensuring furthermore that the binary object is independent of the multiprecision kernel. Slower than copy_bin.

GEN bin_copy(GENbin *p) assuming p was created by copy_bin(x) (not necessarily by the same PARI instance: transmission or external storage may be involved), restores x on the PARI stack.

@3The routine bin_copy transparently encapsulate the following functions:

GEN GENbinbase(GENbin *p) the GEN data actually stored in p. All addresses are stored as offsets with respect to a common reference point, so the resulting GEN is unusable unless it is a non-recursive type; private low-level routines must be called first to restore absolute addresses.

void shiftaddress(GEN x, long dec) converts relative addresses to absolute ones.

void shiftaddress_canon(GEN x, long dec) converts relative addresses to absolute ones, and converts leaves from a canonical form to the one specific to the multiprecision kernel in use. The GENbin type stores whether leaves are stored in canonical form, so bin_copy can call the right variant.

@3Objects containing closures are harder to e.g. copy and save to disk, since closures contain pointers to libpari functions that will not be valid in another gp instance: there is little chance for them to be loaded at the exact same address in memory. Such objects must be saved along with a linking table.

GEN copybin_unlink(GEN C) returns a linking table allowing to safely store and transmit t_CLOSURE objects in C. If C = NULL return a linking table corresponding to the content of all gp variables. C may then be dumped to disk in binary form, for instance.

void bincopy_relink(GEN C, GEN V) given a binary object C, as dumped by writebin and read back into a session, and a linking table V, restore all closures contained in C (function pointers are translated to their current value).

## Garbage collection

See "Label se:garbage" for a detailed explanation and many examples.

void cgiv(GEN x) frees object x, assuming it is the last created on the stack.

GEN gerepile(pari_sp p, pari_sp q, GEN x) general garbage collector for the stack.

void gerepileall(pari_sp av, int n, ...) cleans up the stack from av on (i.e from avma to av), preserving the n objects which follow in the argument list (of type GEN*). For instance, gerepileall(av, 2, &x, &y) preserves x and y.

void gerepileallsp(pari_sp av, pari_sp ltop, int n, ...) cleans up the stack between av and ltop, updating the n elements which follow n in the argument list (of type GEN*). Check that the elements of g have no component between av and ltop, and assumes that no garbage is present between avma and ltop. Analogous to (but faster than) gerepileall otherwise.

GEN gerepilecopy(pari_sp av, GEN x) cleans up the stack from av on, preserving the object x. Special case of gerepileall (case n = 1), except that the routine returns the preserved GEN instead of updating its address through a pointer.

void gerepilemany(pari_sp av, GEN* g[], int n) alternative interface to gerepileall. The preserved GENs are the elements of the array g of length n: g[0], g[1],..., g[n-1]. Obsolete: no more efficient than gerepileall, error-prone, and clumsy (need to declare an extra GEN *g).

void gerepilemanysp(pari_sp av, pari_sp ltop, GEN* g[], int n) alternative interface to gerepileallsp. Obsolete.

void gerepilecoeffs(pari_sp av, GEN x, int n) cleans up the stack from av on, preserving x[0],..., x[n-1] (which are GENs).

void gerepilecoeffssp(pari_sp av, pari_sp ltop, GEN x, int n) cleans up the stack from av to ltop, preserving x[0], ..., x[n-1] (which are GENs). Same assumptions as in gerepilemanysp, of which this is a variant. For instance

    z = cgetg(3, t_COMPLEX);
av = avma; garbage(); ltop = avma;
z[1] = fun1();
z[2] = fun2();
gerepilecoeffssp(av, ltop, z + 1, 2);
return z;

cleans up the garbage between av and ltop, and connects z and its two components. This is marginally more efficient than the standard

    av = avma; garbage(); ltop = avma;
z = cgetg(3, t_COMPLEX);
z[1] = fun1();
z[2] = fun2(); return gerepile(av, ltop, z);

GEN gerepileupto(pari_sp av, GEN q) analogous to (but faster than) gerepilecopy. Assumes that q is connected and that its root was created before any component. If q is not on the stack, this is equivalent to avma = av; in particular, sentinels which are not even proper GENs such as q = NULL are allowed.

GEN gerepileuptoint(pari_sp av, GEN q) analogous to (but faster than) gerepileupto. Assumes further that q is a t_INT. The length and effective length of the resulting t_INT are equal.

GEN gerepileuptoleaf(pari_sp av, GEN q) analogous to (but faster than) gerepileupto. Assumes further that q is a leaf, i.e a non-recursive type (is_recursive_t(typ(q)) is non-zero). Contrary to gerepileuptoint and gerepileupto, gerepileuptoleaf leaves length and effective length of a t_INT unchanged.

void stackdummy(pari_sp av, pari_sp ltop) inhibits the memory area between av included and ltop excluded with respect to gerepile, in order to avoid a call to gerepile(av, ltop,...). The stack space is not reclaimed though.

More precisely, this routine assumes that av is recorded earlier than ltop, then marks the specified stack segment as a non-recursive type of the correct length. Thus gerepile will not inspect the zone, at most copy it. To be used in the following situation:

    av0 = avma; z = cgetg(t_VEC, 3);
gel(z,1) = HUGE(); av = avma; garbage(); ltop = avma;
gel(z,2) = HUGE(); stackdummy(av, ltop);

Compared to the orthodox

    gel(z,2) = gerepile(av, ltop, gel(z,2));

or even more wasteful

    z = gerepilecopy(av0, z);

we temporarily lose (av - ltop) words but save a costly gerepile. In principle, a garbage collection higher up the call chain should reclaim this later anyway.

Without the stackdummy, if the [av, ltop] zone is arbitrary (not even valid GENs as could happen after direct truncation via setlg), we would leave dangerous data in the middle of z, which would be a problem for a later

    gerepile(..., ... , z);

And even if it were made of valid GENs, inhibiting the area makes sure gerepile will not inspect their components, saving time.

Another natural use in low-level routines is to shorten'' an existing GEN z to its first n-1 components:

    setlg(z, n);
stackdummy((pari_sp)(z + lg(z)), (pari_sp)(z + n));

or to its last n components:

    long L = lg(z) - n, tz = typ(z);
stackdummy((pari_sp)(z + L), (pari_sp)z);
z += L; z[0] = evaltyp(tz) | evallg(L);

The first scenario (safe shortening an existing GEN) is in fact so common, that we provide a function for this:

void fixlg(GEN z, long ly) a safe variant of setlg(z, ly). If ly is larger than lg(z) do nothing. Otherwise, shorten z in place, using stackdummy to avoid later gerepile problems.

GEN gcopy_avma(GEN x, pari_sp *AVMA) return a copy of x as from gcopy, except that we pretend that initially avma is *AVMA, and that *AVMA is updated accordingly (so that the total size of x is the difference between the two successive values of *AVMA). It is not necessary for *AVMA to initially point on the stack: gclone is implemented using this mechanism.

GEN icopy_avma(GEN x, pari_sp av) analogous to gcopy_avma but simpler: assume x is a t_INT and return a copy allocated as if initially we had avma equal to av. There is no need to pass a pointer and update the value of the second argument: the new (fictitious) avma is just the return value (typecast to pari_sp).

## Debugging the PARI stack

int chk_gerepileupto(GEN x) returns 1 if x is suitable for gerepileupto, and 0 otherwise. In the latter case, print a warning explaining the problem.

void dbg_gerepile(pari_sp ltop) outputs the list of all objects on the stack between avma and ltop, i.e. the ones that would be inspected in a call to gerepile(...,ltop,...).

void dbg_gerepileupto(GEN q) outputs the list of all objects on the stack that would be inspected in a call to gerepileupto(...,q).

## Copies

GEN gcopy(GEN x) creates a new copy of x on the stack.

GEN gcopy_lg(GEN x, long l) creates a new copy of x on the stack, pretending that lg(x) is l, which must be less than or equal to lg(x). If equal, the function is equivalent to gcopy(x).

int isonstack(GEN x) true iff x belongs to the stack.

void copyifstack(GEN x, GEN y) sets y = gcopy(x) if x belongs to the stack, and y = x otherwise. This macro evaluates its arguments once, contrary to

    y = isonstack(x)? gcopy(x): x;

void icopyifstack(GEN x, GEN y) as copyifstack assuming x is a t_INT.

## Simplify

GEN simplify(GEN x) you should not need that function in library mode. One rather uses:

GEN simplify_shallow(GEN x) shallow, faster, version of simplify.

# The PARI heap

## Introduction

It is implemented as a doubly-linked list of malloc'ed blocks of memory, equipped with reference counts. Each block has type GEN but need not be a valid GEN: it is a chunk of data preceded by a hidden header (meaning that we allocate x and return x + header size). A clone, created by gclone, is a block which is a valid GEN and whose clone bit is set.

## Public interface

GEN newblock(size_t n) allocates a block of n words (not bytes).

void killblock(GEN x) deletes the block x created by newblock. Fatal error if x not a block.

GEN gclone(GEN x) creates a new permanent copy of x on the heap (allocated using newblock). The clone bit of the result is set.

GEN gcloneref(GEN x) if x is not a clone, clone it and return the result; otherwise, increase the clone reference count and return x.

void gunclone(GEN x) deletes a clone. Deletion at first only decreases the reference count by 1. If the count remains positive, no further action is taken; if the count becomes zero, then the clone is actually deleted. In the current implementation, this is an alias for killblock, but it is cleaner to kill clones (valid GENs) using this function, and other blocks using killblock.

void gunclone_deep(GEN x) is only useful in the context of the GP interpreter which may replace arbitrary components of container types (t_VEC, t_COL, t_MAT, t_LIST) by clones. If x is such a container, the function recursively deletes all clones among the components of x, then unclones x. Useless in library mode: simply use gunclone.

void traverseheap(void(*f)(GEN, void *), void *data) this applies f(x, data) to each object x on the PARI heap, most recent first. Mostly for debugging purposes.

GEN getheap() a simple wrapper around traverseheap. Returns a two-component row vector giving the number of objects on the heap and the amount of memory they occupy in long words.

GEN cgetg_block(long x, long y) as cgetg(x,y), creating the return value as a block, not on the PARI stack.

GEN cgetr_block(long prec) as cgetr(prec), creating the return value as a block, not on the PARI stack.

## Implementation note

The hidden block header is manipulated using the following private functions:

void* bl_base(GEN x) returns the pointer that was actually allocated by malloc (can be freed).

long bl_refc(GEN x) the reference count of x: the number of pointers to this block. Decremented in killblock, incremented by the private function void gclone_refc(GEN x); block is freed when the reference count reaches 0.

long bl_num(GEN x) the index of this block in the list of all blocks allocated so far (including freed blocks). Uniquely identifies a block until 2^BIL blocks have been allocated and this wraps around.

GEN bl_next(GEN x) the block after x in the linked list of blocks (NULL if x is the last block allocated not yet killed).

GEN bl_prev(GEN x) the block allocated before x (never NULL).

We documented the last four routines as functions for clarity (and type checking) but they are actually macros yielding valid lvalues. It is allowed to write bl_refc(x)++ for instance.

# Handling user and temp variables

Low-level implementation of user / temporary variables is liable to change. We describe it nevertheless for completeness. Currently variables are implemented by a single array of values divided in 3 zones: 0--nvar (user variables), max_avail--MAXVARN (temporary variables), and nvar+1--max_avail-1 (pool of free variable numbers).

## Low-level

void pari_var_init(): a small part of pari_init. Resets variable counters nvar and max_avail, notwithstanding existing variables! In effect, this even deletes x. Don't use it.

void pari_var_close(void) attached destructor, called by pari_close.

long pari_var_next(): returns nvar, the number of the next user variable we can create.

long pari_var_next_temp() returns max_avail, the number of the next temp variable we can create.

long pari_var_create(entree *ep) low-level initialization of an EpVAR. Return the attached (new) variable number.

GEN vars_sort_inplace(GEN z) given a t_VECSMALL z of variable numbers, sort z in place according to variable priorities (highest priority comes first).

GEN vars_to_RgXV(GEN h) given a t_VECSMALL z of variable numbers, return the t_VEC of pol_x(z[i]).

## User variables

long fetch_user_var(char *s) returns a user variable whose name is s, creating it is needed (and using an existing variable otherwise). Returns its variable number.

GEN fetch_var_value(long v) returns a shallow copy of the current value of the variable numbered v. Return NULL for a temporary variable.

entree* is_entry(const char *s) returns the entree* attached to an identifier s (variable or function), from the interpreter hashtables. Return NULL is the identifier is unknown.

## Temporary variables

long fetch_var(void) returns the number of a new temporary variable (decreasing max_avail).

long delete_var(void) delete latest temp variable created and return the number of previous one.

void name_var(long n, char *s) rename temporary variable number n to s; mostly useful for nicer printout. Error when trying to rename a user variable.

## Nota Bene

As mentioned in the COPYING file, modified versions of the PARI package can be distributed under the conditions of the GNU General Public License. If you do modify PARI, however, it is certainly for a good reason, and we would like to know about it, so that everyone can benefit from your changes. There is then a good chance that your improvements are incorporated into the next release.

We classify changes to PARI into four rough classes, where changes of the first three types are almost certain to be accepted. The first type includes all improvements to the documentation, in a broad sense. This includes correcting typos or inaccuracies of course, but also items which are not really covered in this document, e.g. if you happen to write a tutorial, or pieces of code exemplifying fine points unduly omitted in the present manual.

The second type is to expand or modify the configuration routines and skeleton files (the Configure script and anything in the config/ subdirectory) so that compilation is possible (or easier, or more efficient) on an operating system previously not catered for. This includes discovering and removing idiosyncrasies in the code that would hinder its portability.

The third type is to modify existing (mathematical) code, either to correct bugs, to add new functionality to existing functions, or to improve their efficiency.

Finally the last type is to add new functions to PARI. We explain here how to do this, so that in particular the new function can be called from gp.

## Coding guidelines

Code your function in a file of its own, using as a guide other functions in the PARI sources. One important thing to remember is to clean the stack before exiting your main function, since otherwise successive calls to the function clutters the stack with unnecessary garbage, and stack overflow occurs sooner. Also, if it returns a GEN and you want it to be accessible to gp, you have to make sure this GEN is suitable for gerepileupto (see "Label se:garbage").

If error messages or warnings are to be generated in your function, use pari_err and pari_warn respectively. Recall that pari_err does not return but ends with a longjmp statement. As well, instead of explicit printf / fprintf statements, use the following encapsulated variants:

void pari_putc(char c): write character c to the output stream.

void pari_puts(char *s): write s to the output stream.

void pari_printf(const char *fmt, ...): write following arguments to the output stream, according to the conversion specifications in format fmt (see printf).

void err_printf(const char *fmt, ...): as pari_printf, writing to PARI's current error stream.

void err_flush(void) flush error stream.

Declare all public functions in an appropriate header file, if you want to access them from C. The other functions should be declared static in your file.

Your function is now ready to be used in library mode after compilation and creation of the library. If possible, compile it as a shared library (see the Makefile coming with the extgcd example in the distribution). It is however still inaccessible from gp.

## GP prototypes, parser codes

A GP prototype is a character string describing all the GP parser needs to know about the function prototype. It contains a sequence of the following atoms:

@3* Return type: GEN by default (must be valid for gerepileupto), otherwise the following can appear as the first char of the code string:

i return int

l return long

u return ulong

v return void

m return a GEN which is not gerepile-safe.

The m code is used for member functions, to avoid unnecessary copies. A copy opcode is generated by the compiler if the result needs to be kept safe for later use.

@3* Mandatory arguments, appearing in the same order as the input arguments they describe:

G GEN

& *GEN

L long (we implicitly typecast int to long)

U ulong

V loop variable

n variable, expects a variable number (a long, not an *entree)

W a GEN which is a lvalue to be modified in place (for t_LIST)

r raw input (treated as a string without quotes). Quoted args are copied as strings

Stops at first unquoted ')' or ','. Special chars can be quoted using '\'

Example: aa"b\n)"c yields the string "aab\n)c"

s expanded string. Example: Pi"x"2 yields "3.142x2"

Unquoted components can be of any PARI type, converted to string following

current output format

I closure whose value is ignored, as in for loops,

to be processed by void closure_evalvoid(GEN C)

E closure whose value is used, as in sum loops,

to be processed by void closure_evalgen(GEN C)

J implicit function of arity 1, as in parsum loops,

to be processed by void closure_callgen1(GEN C)

@3A closure is a GP function in compiled (bytecode) form. It can be efficiently evaluated using the closure_evalxxx functions.

@3* Automatic arguments:

f Fake *long. C function requires a pointer but we do not use the resulting long

b current real precision in bits

p current real precision in words

P series precision (default seriesprecision, global variable precdl for the library)

C lexical context (internal, for eval, see localvars_read_str)

@3* Syntax requirements, used by functions like for, sum, etc.:

 =  separator  =  required at this point (between two arguments)

@3* Optional arguments and default values:

E* any number of expressions, possibly 0 (see E)

s* any number of strings, possibly 0 (see s)

Dxxx argument can be omitted and has a default value

The E* code reads all remaining arguments in closure context and passes them as a single t_VEC. The s* code reads all remaining arguments in string context and passes the list of strings as a single t_VEC. The automatic concatenation rules in string context are implemented so that adjacent strings are read as different arguments, as if they had been comma-separated. For instance, if the remaining argument sequence is: "xx" 1, "yy", the s* atom sends [a, b, c], where a, b, c are GENs of type t_STR (content "xx"), t_INT (equal to 1) and t_STR (content "yy").

The format to indicate a default value (atom starts with a D) is Dvalue,type,'', where type is the code for any mandatory atom (previous group), value is any valid GP expression which is converted according to type, and the ending comma is mandatory. For instance D0,L, stands for this optional argument is converted to a long, and is 0 by default''. So if the user-given argument reads 1 + 3 at this point, 4L is sent to the function; and 0L if the argument is omitted. The following special notations are available:

DG optional GEN, send NULL if argument omitted.

D& optional *GEN, send NULL if argument omitted.

The argument must be prefixed by &.

DI, DE optional closure, send NULL if argument omitted.

DP optional long, send precdl if argument omitted.

DV optional *entree, send NULL if argument omitted.

Dn optional variable number, -1 if omitted.

Dr optional raw string, send NULL if argument omitted.

Ds optional char *, send NULL if argument omitted.

@3Hardcoded limit. C functions using more than 20 arguments are not supported. Use vectors if you really need that many parameters.

When the function is called under gp, the prototype is scanned and each time an atom corresponding to a mandatory argument is met, a user-given argument is read (gp outputs an error message it the argument was missing). Each time an optional atom is met, a default value is inserted if the user omits the argument. The automatic'' atoms fill in the argument list transparently, supplying the current value of the corresponding variable (or a dummy pointer).

For instance, here is how you would code the following prototypes, which do not involve default values:

  GEN f(GEN x, GEN y, long prec)   ----> "GGp"
void f(GEN x, GEN y, long prec)  ----> "vGGp"
void f(GEN x, long y, long prec) ----> "vGLp"
long f(GEN x)                    ----> "lG"
int f(long x)                    ----> "iL"

If you want more examples, gp gives you easy access to the parser codes attached to all GP functions: just type \h function. You can then compare with the C prototypes as they stand in paridecl.h.

@3Remark. If you need to implement complicated control statements (probably for some improved summation functions), you need to know how the parser implements closures and lexicals and how the evaluator lets you deal with them, in particular the push_lex and pop_lex functions. Check their descriptions and adapt the source code in language/sumiter.c and language/intnum.c.

## Integration with gp as a shared module

In this section we assume that your Operating System is supported by install. You have written a function in C following the guidelines is "Label se:coding_guidelines"; in case the function returns a GEN, it must satisfy gerepileupto assumptions (see "Label se:garbage").

You then succeeded in building it as part of a shared library and want to finally tell gp about your function. First, find a name for it. It does not have to match the one used in library mode, but consistency is nice. It has to be a valid GP identifier, i.e. use only alphabetic characters, digits and the underscore character (_), the first character being alphabetic.

Then figure out the correct parser code corresponding to the function prototype (as explained in "Label se:gp.interface") and write a GP script like the following:

  install(libname, code, gpname, library)
addhelp(gpname, "some help text")

@3The addhelp part is not mandatory, but very useful if you want others to use your module. libname is how the function is named in the library, usually the same name as one visible from C.

Read that file from your gp session, for instance from your preferences file (or gprc), and that's it. You can now use the new function gpname under gp, and we would very much like to hear about it!

@3Example. A complete description could look like this:

  {
install(bnfinit0, "GD0,L,DGp", ClassGroupInit, "libpari.so");
compute the necessary data for ...");
}

@3which means we have a function ClassGroupInit under gp, which calls the library function bnfinit0 . The function has one mandatory argument, and possibly two more (two 'D' in the code), plus the current real precision. More precisely, the first argument is a GEN, the second one is converted to a long using itos (0 is passed if it is omitted), and the third one is also a GEN, but we pass NULL if no argument was supplied by the user. This matches the C prototype (from paridecl.h):

    GEN bnfinit0(GEN P, long flag, GEN data, long prec)

This function is in fact coded in basemath/buch2.c, and is in this case completely identical to the GP function bnfinit but gp does not need to know about this, only that it can be found somewhere in the shared library libpari.so.

@3Important note. You see in this example that it is the function's responsibility to correctly interpret its operands: data = NULL is interpreted by the function as an empty vector. Note that since NULL is never a valid GEN pointer, this trick always enables you to distinguish between a default value and actual input: the user could explicitly supply an empty vector!

## Library interface for install

There is a corresponding library interface for this install functionality, letting you expand the GP parser/evaluator available in the library with new functions from your C source code. Functions such as gp_read_str may then evaluate a GP expression sequence involving calls to these new function!

entree * install(void *f, const char *gpname, const char *code)

@3where f is the (address of the) function (cast to void*), gpname is the name by which you want to access your function from within your GP expressions, and code is as above.

## Integration by patching gp

If install is not available, and installing Linux or a BSD operating system is not an option (why?), you have to hardcode your function in the gp binary. Here is what needs to be done:

@3* Fetch the complete sources of the PARI distribution.

@3* Drop the function source code module in an appropriate directory (a priori src/modules), and declare all public functions in src/headers/paridecl.h.

@3* Choose a help section and add a file src/functions/section/gpname containing the following, keeping the notation above:

  Function:  I<gpname>
Section:   I<section>
C-Name:    I<libname>
Prototype: I<code>
Help:      I<some help text>

(If the help text does not fit on a single line, continuation lines must start by a whitespace character.) Two GP2C-related fields (Description and Wrapper) are also available to improve the code GP2C generates when compiling scripts involving your function. See the GP2C documentation for details.

@3* Launch Configure, which should pick up your C files and build an appropriate Makefile. At this point you can recompile gp, which will first rebuild the functions database.

@3Example. We reuse the ClassGroupInit / bnfinit0 from the preceding section. Since the C source code is already part of PARI, we only need to add a file

functions/number_fields/ClassGroupInit

@3containing the following:

  Function: ClassGroupInit
Section: number_fields
C-Name: bnfinit0
Prototype: GD0,L,DGp
Help: ClassGroupInit(P,{flag=0},{tech=[]}): this routine does ...

and recompile gp.

# Globals related to PARI configuration

## PARI version numbers

@3paricfg_version_code encodes in a single long, the Major and minor version numbers as well as the patchlevel.

long PARI_VERSION(long M, long m, long p) produces the version code attached to release M.m.p. Each code identifies a unique PARI release, and corresponds to the natural total order on the set of releases (bigger code number means more recent release).

@3PARI_VERSION_SHIFT is the number of bits used to store each of the integers M, m, p in the version code.

@3paricfg_vcsversion is a version string related to the revision control system used to handle your sources, if any. For instance git-commit hash if compiled from a git repository.

The two character strings paricfg_version and paricfg_buildinfo, correspond to the first two lines printed by gp just before the Copyright message. The character string paricfg_compiledate is the date of compilation which appears on the next line. The character string paricfg_mt_engine is the name of the threading engine on the next line.

GEN pari_version() returns the version number as a PARI object, a t_VEC with three t_INT and one t_STR components.

## Miscellaneous

paricfg_datadir: character string. The location of PARI's datadir.

\newpage

# NAME

libPARI - Arithmetic kernel: Level 0 and 1

# Level 0 kernel (operations on ulongs)

## Micro-kernel

The Level 0 kernel simulates basic operations of the 68020 processor on which PARI was originally implemented. They need global'' ulong variables overflow (which will contain only 0 or 1) and hiremainder to function properly. A routine using one of these lowest-level functions where the description mentions either hiremainder or overflow must declare the corresponding

    LOCAL_HIREMAINDER;  /* provides 'hiremainder' */
LOCAL_OVERFLOW;     /* provides 'overflow' */

in a declaration block. Variables hiremainder and overflow then become available in the enclosing block. For instance a loop over the powers of an ulong p protected from overflows could read

   while (pk < lim)
{
LOCAL_HIREMAINDER;
...
pk = mulll(pk, p); if (hiremainder) break;
}

For most architectures, the functions mentioned below are really chunks of inlined assembler code, and the above global' variables are actually local register values.

ulong addll(ulong x, ulong y) adds x and y, returns the lower BIL bits and puts the carry bit into overflow.

ulong addllx(ulong x, ulong y) adds overflow to the sum of the x and y, returns the lower BIL bits and puts the carry bit into overflow.

ulong subll(ulong x, ulong y) subtracts x and y, returns the lower BIL bits and put the carry (borrow) bit into overflow.

ulong subllx(ulong x, ulong y) subtracts overflow from the difference of x and y, returns the lower BIL bits and puts the carry (borrow) bit into overflow.

int bfffo(ulong x) returns the number of leading zero bits in x. That is, the number of bit positions by which it would have to be shifted left until its leftmost bit first becomes equal to 1, which can be between 0 and BIL-1 for nonzero x. When x is 0, the result is undefined.

ulong mulll(ulong x, ulong y) multiplies x by y, returns the lower BIL bits and stores the high-order BIL bits into hiremainder.

ulong addmul(ulong x, ulong y) adds hiremainder to the product of x and y, returns the lower BIL bits and stores the high-order BIL bits into hiremainder.

ulong divll(ulong x, ulong y) returns the quotient of  (hiremainder * 2^{BIL}) + x  by y and stores the remainder into hiremainder. An error occurs if the quotient cannot be represented by an ulong, i.e. if initially hiremainder >= y.

@3Obsolete routines. Those functions are awkward and no longer used; they are only provided for backward compatibility:

ulong shiftl(ulong x, ulong y) returns x shifted left by y bits, i.e. x << y, where we assume that 0 <= y <= BIL. The global variable hiremainder receives the bits that were shifted out, i.e. x >> (BIL - y).

ulong shiftlr(ulong x, ulong y) returns x shifted right by y bits, i.e. x >> y, where we assume that 0 <= y <= BIL. The global variable hiremainder receives the bits that were shifted out, i.e. x << (BIL - y).

## Modular kernel

The following routines are not part of the level 0 kernel per se, but implement modular operations on words in terms of the above. They are written so that no overflow may occur. Let m >= 1 be the modulus; all operands representing classes modulo m are assumed to belong to [0,m-1]. The result may be wrong for a number of reasons otherwise: it may not be reduced, overflow can occur, etc.

int odd(ulong x) returns 1 if x is odd, and 0 otherwise.

int both_odd(ulong x, ulong y) returns 1 if x and y are both odd, and 0 otherwise.

ulong invmod2BIL(ulong x) returns the smallest positive representative of x^{-1} mod 2^BIL, assuming x is odd.

ulong Fl_add(ulong x, ulong y, ulong m) returns the smallest positive representative of x + y modulo m.

ulong Fl_neg(ulong x, ulong m) returns the smallest positive representative of -x modulo m.

ulong Fl_sub(ulong x, ulong y, ulong m) returns the smallest positive representative of x - y modulo m.

long Fl_center(ulong x, ulong m, ulong mo2) returns the representative in ]-m/2,m/2] of x modulo m. Assume 0 <= x < m and mo2 = m >> 1.

ulong Fl_mul(ulong x, ulong y, ulong m) returns the smallest positive representative of x y modulo m.

ulong Fl_double(ulong x, ulong m) returns 2x modulo m.

ulong Fl_triple(ulong x, ulong m) returns 3x modulo m.

ulong Fl_halve(ulong x, ulong m) returns z such that 2 z = x modulo m assuming such z exists.

ulong Fl_sqr(ulong x, ulong m) returns the smallest positive representative of x^2 modulo m.

ulong Fl_inv(ulong x, ulong m) returns the smallest positive representative of x^{-1} modulo m. If x is not invertible mod m, raise an exception.

ulong Fl_invsafe(ulong x, ulong m) returns the smallest positive representative of x^{-1} modulo m. If x is not invertible mod m, return 0 (which is ambiguous if m = 1).

ulong Fl_invgen(ulong x, ulong m, ulong *pg) set *pg to g =  gcd (x,m) and return u (invertible) such that x u = g modulo m. We have g = 1 if and only if x is invertible, and in this case u is its inverse.

ulong Fl_div(ulong x, ulong y, ulong m) returns the smallest positive representative of x y^{-1} modulo m. If y is not invertible mod m, raise an exception.

ulong Fl_powu(ulong x, ulong n, ulong m) returns the smallest positive representative of x^n modulo m.

GEN Fl_powers(ulong x, long n, ulong p) returns [x^0,..., x^n] modulo m, as a t_VECSMALL.

ulong Fl_sqrt(ulong x, ulong p) returns the square root of x modulo p (smallest positive representative). Assumes p to be prime, and x to be a square modulo p.

ulong Fl_sqrtl(ulong x, ulong l, ulong p) returns a l-the root of x modulo p. Assumes p to be prime and p = 1 (mod l), and x to be a l-th power modulo p.

ulong Fl_order(ulong a, ulong o, ulong p) returns the order of the Fp a. It is assumed that o is a multiple of the order of a, 0 being allowed (no non-trivial information).

ulong random_Fl(ulong p) returns a pseudo-random integer uniformly distributed in 0, 1,...p-1.

ulong pgener_Fl(ulong p) returns the smallest primitive root modulo p, assuming p is prime.

ulong pgener_Zl(ulong p) returns the smallest primitive root modulo p^k, k > 1, assuming p is an odd prime.

ulong pgener_Fl_local(ulong p, GEN L), see gener_Fp_local, L is an Flv.

## Modular kernel with precomputed inverse''

This is based on an algorithm by T. Grandlund and N. Möller in Improved division by invariant integers'' http://gmplib.org/~tege/division-paper.pdf.

In the following, we set B = BIL.

ulong get_Fl_red(ulong p) returns a pseudo inverse pi for p

ulong divll_pre(ulong x, ulong p, ulong yi) as divll, where yi is the pseudo inverse of y.

ulong remll_pre(ulong u1, ulong u0, ulong p, ulong pi) returns the Euclidean remainder of u_1 2^B+u_0 modulo p, assuming pi is the pseudo inverse of p. This function is faster if u_1 < p.

ulong remlll_pre(ulong u2, ulong u1, ulong u0, ulong p, ulong pi) returns the Euclidean remainder of u_2 2^{2 B}+u_1 2^{B}+u_0 modulo p, assuming pi is the pseudo inverse of p.

ulong Fl_sqr_pre(ulong x, ulong p, ulong pi) returns x^2 modulo p, assuming pi is the pseudo inverse of p.

ulong Fl_mul_pre(ulong x, ulong y, ulong p, ulong pi) returns x y modulo p, assuming pi is the pseudo inverse of p.

ulong Fl_addmul_pre(ulong a, ulong b, ulong c, ulong p, ulong pi) returns a b+c modulo p, assuming pi is the pseudo inverse of p.

ulong Fl_addmulmul_pre(ulong a,ulong b, ulong c,ulong d, ulong p, ulong pi) returns a b+c d modulo p, assuming pi is the pseudo inverse of p.

ulong Fl_powu_pre(ulong x, ulong n, ulong p, ulong pi) returns x^n modulo p, assuming pi is the pseudo inverse of p.

GEN Fl_powers_pre(ulong x, long n, ulong p, ulong pi) returns the vector (t_VECSMALL) (x^0,..., x^n), assuming pi is the pseudo inverse of p.

ulong Fl_sqrt_pre(ulong x, ulong p, ulong pi) returns a square root of x modulo p, assuming pi is the pseudo inverse of p. See Fl_sqrt.

ulong Fl_sqrtl_pre(ulong x, ulong l, ulong p, ulong pi) returns a l-the root of x modulo p, assuming pi is the pseudo inverse of p, p prime and p = 1 (mod l), and x to be a l-th power modulo p.

## Switching between Fl_xxx and standard operators

Even though the Fl_xxx routines are efficient, they are slower than ordinary long operations, using the standard +, %, etc. operators. The following macro is used to choose in a portable way the most efficient functions for given operands:

int SMALL_ULONG(ulong p) true if 2p^2 < 2^BIL. In that case, it is possible to use ordinary operators efficiently. If p < 2^BIL, one may still use the Fl_xxx routines. Otherwise, one must use generic routines. For instance, the scalar product of the GENs x and y mod p could be computed as follows.

      long i, l = lg(x);
if (lgefint(p) > 3)
{ /* arbitrary */
GEN s = gen_0;
for (i = 1; i < l; i++) s = addii(s, mulii(gel(x,i), gel(y,i)));
return modii(s, p).
}
else
{
ulong s = 0, pp = itou(p);
x = ZV_to_Flv(x, pp);
y = ZV_to_Flv(y, pp);
if (SMALL_ULONG(pp))
{ /* very small */
for (i = 1; i < l; i++)
{
s += x[i] * y[i];
if (s & HIGHBIT) s %= pp;
}
s %= pp;
}
else
{ /* small */
for (i = 1; i < l; i++)
s = Fl_add(s, Fl_mul(x[i], y[i], pp), pp);
}
return utoi(s);
}

In effect, we have three versions of the same code: very small, small, and arbitrary inputs. The very small and arbitrary variants use lazy reduction and reduce only when it becomes necessary: when overflow might occur (very small), and at the very end (very small, arbitrary).

# Level 1 kernel (operations on longs, integers and reals)

@3Note. Some functions consist of an elementary operation, immediately followed by an assignment statement. They will be introduced as in the following example:

GEN gadd[z](GEN x, GEN y[, GEN z]) followed by the explicit description of the function

GEN gadd(GEN x, GEN y)

@3which creates its result on the stack, returning a GEN pointer to it, and the parts in brackets indicate that there exists also a function

void gaddz(GEN x, GEN y, GEN z)

@3which assigns its result to the pre-existing object z, leaving the stack unchanged. These assignment variants are kept for backward compatibility but are inefficient: don't use them.

## Creation

GEN cgeti(long n) allocates memory on the PARI stack for a t_INT of length n, and initializes its first codeword. Identical to cgetg(n,t_INT).

GEN cgetipos(long n) allocates memory on the PARI stack for a t_INT of length n, and initializes its two codewords. The sign of n is set to 1.

GEN cgetineg(long n) allocates memory on the PARI stack for a negative t_INT of length n, and initializes its two codewords. The sign of n is set to -1.

GEN cgetr(long n) allocates memory on the PARI stack for a t_REAL of length n, and initializes its first codeword. Identical to cgetg(n,t_REAL).

GEN cgetc(long n) allocates memory on the PARI stack for a t_COMPLEX, whose real and imaginary parts are t_REALs of length n.

GEN real_1(long prec) create a t_REAL equal to 1 to prec words of accuracy.

GEN real_1_bit(long bitprec) create a t_REAL equal to 1 to bitprec bits of accuracy.

GEN real_m1(long prec) create a t_REAL equal to -1 to prec words of accuracy.

GEN real_0_bit(long bit) create a t_REAL equal to 0 with exponent -bit.

GEN real_0(long prec) is a shorthand for

    real_0_bit( -prec2nbits(prec) )

GEN int2n(long n) creates a t_INT equal to 1 << n (i.e 2^n if n >= 0, and 0 otherwise).

GEN int2u(ulong n) creates a t_INT equal to 2^n.

GEN real2n(long n, long prec) create a t_REAL equal to 2^n to prec words of accuracy.

GEN real_m2n(long n, long prec) create a t_REAL equal to -2^n to prec words of accuracy.

GEN strtoi(char *s) convert the character string s to a non-negative t_INT. Decimal numbers, hexadecimal numbers prefixed by 0x and binary numbers prefixed by 0b are allowed. The string s consists exclusively of digits: no leading sign, no whitespace. Leading zeroes are discarded.

GEN strtor(char *s, long prec) convert the character string s to a non-negative t_REAL of precision prec. The string s consists exclusively of digits and optional decimal point and exponent (e or E): no leading sign, no whitespace. Leading zeroes are discarded.

## Assignment

In this section, the z argument in the z-functions must be of type t_INT or t_REAL.

void mpaff(GEN x, GEN z) assigns x into z (where x and z are t_INT or t_REAL). Assumes that lg(z) > 2.

void affii(GEN x, GEN z) assigns the t_INT x into the t_INT z.

void affir(GEN x, GEN z) assigns the t_INT x into the t_REAL z. Assumes that lg(z) > 2.

void affiz(GEN x, GEN z) assigns t_INT x into t_INT or t_REAL z. Assumes that lg(z) > 2.

void affsi(long s, GEN z) assigns the long s into the t_INT z. Assumes that lg(z) > 2.

void affsr(long s, GEN z) assigns the long s into the t_REAL z. Assumes that lg(z) > 2.

void affsz(long s, GEN z) assigns the long s into the t_INT or t_REAL z. Assumes that lg(z) > 2.

void affui(ulong u, GEN z) assigns the ulong u into the t_INT z. Assumes that lg(z) > 2.

void affur(ulong u, GEN z) assigns the ulong u into the t_REAL z. Assumes that lg(z) > 2.

void affrr(GEN x, GEN z) assigns the t_REAL x into the t_REAL z.

void affgr(GEN x, GEN z) assigns the scalar x into the t_REAL z, if possible.

@3The function affrs and affri do not exist. So don't use them.

void affrr_fixlg(GEN y, GEN z) a variant of affrr. First shorten z so that it is no longer than y, then assigns y to z. This is used in the following scenario: room is reserved for the result but, due to cancellation, fewer words of accuracy are available than had been anticipated; instead of appending meaningless 0s to the mantissa, we store what was actually computed.

Note that shortening z is not quite straightforward, since setlg(z, ly) would leave garbage on the stack, which gerepile might later inspect. It is done using

void fixlg(GEN z, long ly) see stackdummy and the examples that follow.

## Copy

GEN icopy(GEN x) copy relevant words of the t_INT x on the stack: the length and effective length of the copy are equal.

GEN rcopy(GEN x) copy the t_REAL x on the stack.

GEN leafcopy(GEN x) copy the leaf x on the stack (works in particular for t_INTs and t_REALs). Contrary to icopy, leafcopy preserves the original length of a t_INT. The obsolete form GEN mpcopy(GEN x) is still provided for backward compatibility.

This function also works on recursive types, copying them as if they were leaves, i.e. making a shallow copy in that case: the components of the copy point to the same data as the component of the source; see also shallowcopy.

GEN leafcopy_avma(GEN x, pari_sp av) analogous to gcopy_avma but simpler: assume x is a leaf and return a copy allocated as if initially we had avma equal to av. There is no need to pass a pointer and update the value of the second argument: the new (fictitious) avma is just the return value (typecast to pari_sp).

GEN icopyspec(GEN x, long nx) copy the nx words x[2],..., x[nx+1] to make up a new t_INT. Set the sign to 1.

## Conversions

GEN itor(GEN x, long prec) converts the t_INT x to a t_REAL of length prec and return the latter. Assumes that prec > 2.

long itos(GEN x) converts the t_INT x to a long if possible, otherwise raise an exception. We consider the conversion to be possible if and only if |x| <= LONG_MAX, i.e. |x| < 2^{63} on a 64-bit architecture. Since the range is symetric, the output of itos can safely be negated.

long itos_or_0(GEN x) converts the t_INT x to a long if possible, otherwise return 0.

int is_bigint(GEN n) true if itos(n) would give an error.

ulong itou(GEN x) converts the t_INT |x| to an ulong if possible, otherwise raise an exception. The conversion is possible if and only if lgefint(x) <= 3.

long itou_or_0(GEN x) converts the t_INT |x| to an ulong if possible, otherwise return 0.

GEN stoi(long s) creates the t_INT corresponding to the long s.

GEN stor(long s, long prec) converts the long s into a t_REAL of length prec and return the latter. Assumes that prec > 2.

GEN utoi(ulong s) converts the ulong s into a t_INT and return the latter.

GEN utoipos(ulong s) converts the non-zero ulong s into a t_INT and return the latter.

GEN utoineg(ulong s) converts the non-zero ulong s into the t_INT -s and return the latter.

GEN utor(ulong s, long prec) converts the ulong s into a t_REAL of length prec and return the latter. Assumes that prec > 2.

GEN rtor(GEN x, long prec) converts the t_REAL x to a t_REAL of length prec and return the latter. If prec < lg(x), round properly. If prec > lg(x), pad with zeroes. Assumes that prec > 2.

@3The following function is also available as a special case of mkintn:

GEN uu32toi(ulong a, ulong b) returns the GEN equal to 2^{32} a + b, assuming that a,b < 2^{32}. This does not depend on sizeof(long): the behavior is as above on both 32 and 64-bit machines.

GEN uutoi(ulong a, ulong b) returns the GEN equal to 2^{BIL} a + b.

GEN uutoineg(ulong a, ulong b) returns the GEN equal to -(2^{BIL} a + b).

## Integer parts

The following four functions implement the conversion from t_REAL to t_INT using standard rounding modes. Contrary to usual semantics (complement the mantissa with an infinite number of 0), they will raise an error precision loss in truncation if the t_REAL represents a range containing more than one integer.

GEN ceilr(GEN x) smallest integer larger or equal to the t_REAL x (i.e. the ceil function).

GEN floorr(GEN x) largest integer smaller or equal to the t_REAL x (i.e. the floor function).

GEN roundr(GEN x) rounds the t_REAL x to the nearest integer (towards + oo  in case of tie).

GEN truncr(GEN x) truncates the t_REAL x (not the same as floorr if x is negative).

The following four function are analogous, but can also treat the trivial case when the argument is a t_INT:

GEN mpceil(GEN x) as ceilr except that x may be a t_INT.

GEN mpfloor(GEN x) as floorr except that x may be a t_INT.

GEN mpround(GEN x) as roundr except that x may be a t_INT.

GEN mptrunc(GEN x) as truncr except that x may be a t_INT.

GEN diviiround(GEN x, GEN y) if x and y are t_INTs, returns the quotient x/y of x and y, rounded to the nearest integer. If x/y falls exactly halfway between two consecutive integers, then it is rounded towards + oo  (as for roundr).

GEN ceil_safe(GEN x), x being a real number (not necessarily a t_REAL) returns the smallest integer which is larger than any possible incarnation of x. (Recall that a t_REAL represents an interval of possible values.) Note that gceil raises an exception if the input accuracy is too low compared to its magnitude.

GEN floor_safe(GEN x), x being a real number (not necessarily a t_REAL) returns the largest integer which is smaller than any possible incarnation of x. (Recall that a t_REAL represents an interval of possible values.) Note that gfloor raises an exception if the input accuracy is too low compared to its magnitude.

GEN trunc_safe(GEN x), x being a real number (not necessarily a t_REAL) returns the integer with the largest absolute value, which is closer to 0 than any possible incarnation of x. (Recall that a t_REAL represents an interval of possible values.)

GEN roundr_safe(GEN x) rounds the t_REAL x to the nearest integer (towards + oo ). Complement the mantissa with an infinite number of 0 before rounding, hence never raise an exception.

## 2-adic valuations and shifts

long vals(long s) 2-adic valuation of the long s. Returns -1 if s is equal to 0.

long vali(GEN x) 2-adic valuation of the t_INT x. Returns -1 if x is equal to 0.

GEN mpshift(GEN x, long n) shifts the t_INT or t_REAL x by n. If n is positive, this is a left shift, i.e. multiplication by 2^{n}. If n is negative, it is a right shift by -n, which amounts to the truncation of the quotient of x by 2^{-n}.

GEN shifti(GEN x, long n) shifts the t_INT x by n.

GEN shiftr(GEN x, long n) shifts the t_REAL x by n.

void shiftr_inplace(GEN x, long n) shifts the t_REAL x by n, in place.

GEN trunc2nr(GEN x, long n) given a t_REAL x, returns truncr(shiftr(x,n)), but faster, without leaving garbage on the stack and never raising a precision loss in truncation error. Called by gtrunc2n.

GEN trunc2nr_lg(GEN x, long lx, long n) given a t_REAL x, returns trunc2nr(x,n), pretending that the length of x is lx, which must be  <= lg(x).

GEN mantissa2nr(GEN x, long n) given a t_REAL x, returns the mantissa of x 2^n (disregards the exponent of x). Equivalent to

    trunc2nr(x, n-expo(x)+bit_prec(x)-1)

GEN mantissa_real(GEN z, long *e) returns the mantissa m of z, and sets *e to the exponent bit_accuracy(lg(z))-1-expo(z), so that z = m / 2^e.

@3Low-level. In the following two functions, s(ource) and t(arget) need not be valid GENs (in practice, they usually point to some part of a t_REAL mantissa): they are considered as arrays of words representing some mantissa, and we shift globally s by n > 0 bits, storing the result in t. We assume that m <= M and only access s[m], s[m+1],...s[M] (read) and likewise for t (write); we may have s = t but more general overlaps are not allowed. The word f is concatenated to s to supply extra bits.

void shift_left(GEN t, GEN s, long m, long M, ulong f, ulong n) shifts the mantissa

s[m], s[m+1],...s[M], f

left by n bits.

void shift_right(GEN t, GEN s, long m, long M, ulong f, ulong n) shifts the mantissa

f, s[m], s[m+1],...s[M]

right by n bits.

## From t_INT to bits or digits in base 2^k and back

GEN binary_zv(GEN x) given a t_INT x, return a t_VECSMALL of bits, from most significant to least significant.

GEN binary_2k(GEN x, long k) given a t_INT x, and k > 0, return a t_VEC of digits of x in base 2^k, as t_INTs, from most significant to least significant.

GEN binary_2k_nv(GEN x, long k) given a t_INT x, and 0 < k < BITS_IN_LONG, return a t_VECSMALL of digits of x in base 2^k, as ulongs, from most significant to least significant.

GEN bits_to_int(GEN x, long l) given a vector x of l bits (as a t_VECSMALL or even a pointer to a part of a larger vector, so not a proper GEN), return the integer sum_{i = 1}^l x[i] 2^{l-i}, as a t_INT.

ulong bits_to_u(GEN v, long l) same as bits_to_int, where l < BITS_IN_LONG, so we can return an ulong.

GEN fromdigitsu(GEN x, GEN B) given a t_VECSMALL x of length l and a t_INT B, return the integer sum_{i = 1}^l x[i] B^{i-1}, as a t_INT, where the x[i] are seen as unsigned integers.

GEN fromdigits_2k(GEN x, long k) converse of binary_2k; given a t_VEC x of length l and a positive long k, where each x[i] is a t_INT with 0 <= x[i] < 2^k, return the integer sum_{i = 1}^l x[i] 2^{k(l-i)}, as a t_INT.

GEN nv_fromdigits_2k(GEN x, long k) as fromdigits_2k, but with x being a t_VECSMALL and each x[i] being a ulong with 0 <= x[i] < 2^{ min {k,BITS_IN_LONG}}. Here k may be any positive long, and the x[i] are regarded as k-bit integers by truncating or extending with zeroes.

## Integer valuation

For integers x and p, such that x != 0 and |p| > 1, we define v_p(x) to be the largest integer exponent e such that p^e divides x. If p is prime, this is the ordinary valuation of x at p.

long Z_pvalrem(GEN x, GEN p, GEN *r) applied to t_INTs x != 0 and p, |p| > 1, returns e := v_p(x) The quotient x/p^e is returned in *r. If |p| is a prime, *r is the prime-to-p part of x.

long Z_pval(GEN x, GEN p) as Z_pvalrem but only returns v_p(x).

long Z_lvalrem(GEN x, ulong p, GEN *r) as Z_pvalrem, except that p is an ulong (p > 1).

long Z_lvalrem_stop(GEN *x, ulong p, int *stop) returns e := v_p(x) and replaces x by x / p^e. Set stop to 1 if the new value of x is  < p^2 (and 0 otherwise). To be used when trial dividing x by successive primes: the stop condition is cheaply tested while testing whether p divides x (is the quotient less than p?), and allows to decide that n is prime if no prime  < p divides n. Not memory-clean.

long Z_lval(GEN x, ulong p) as Z_pval, except that p is an ulong (p > 1).

long u_lvalrem(ulong x, ulong p, ulong *r) as Z_pvalrem, except the inputs/outputs are now ulongs.

long u_lvalrem_stop(ulong *n, ulong p, int *stop) as Z_pvalrem_stop.

long u_pvalrem(ulong x, GEN p, ulong *r) as Z_pvalrem, except x and r are now ulongs.

long u_lval(ulong x, ulong p) as Z_pval, except the inputs are now ulongs.

long u_pval(ulong x, GEN p) as Z_pval, except x is now an ulong.

long z_lval(long x, ulong p) as u_lval, for signed x.

long z_lvalrem(long x, ulong p) as u_lvalrem, for signed x.

long z_pval(long x, GEN p) as Z_pval, except x is now a long.

long z_pvalrem(long x, GEN p) as Z_pvalrem, except x is now a long.

long Q_pval(GEN x, GEN p) valuation at the t_INT p of the t_INT or t_FRAC x.

long factorial_lval(ulong n, ulong p) returns v_p(n!), assuming p is prime.

The following convenience functions generalize Z_pval and its variants to containers'' (ZV and ZX):

long ZV_pvalrem(GEN x, GEN p, GEN *r) x being a ZV (a vector of t_INTs), return the min v of the valuations of its components and set *r to x/p^v. Infinite loop if x is the zero vector. This function is not stack clean.

long ZV_pval(GEN x, GEN p) as ZV_pvalrem but only returns the valuation''.

int ZV_Z_dvd(GEN x, GEN p) returns 1 if p divides all components of x and 0 otherwise. Faster than testing ZV_pval(x,p) >= 1.

long ZV_lvalrem(GEN x, ulong p, GEN *px) as ZV_pvalrem, except that p is an ulong (p > 1). This function is not stack-clean.

long ZV_lval(GEN x, ulong p) as ZV_pval, except that p is an ulong (p > 1).

long ZX_pvalrem(GEN x, GEN p, GEN *r) as ZV_pvalrem, for a ZX x (a t_POL with t_INT coefficients). This function is not stack-clean.

long ZX_pval(GEN x, GEN p) as ZV_pval for a ZX x.

long ZX_lvalrem(GEN x, ulong p, GEN *px) as ZV_lvalrem, a ZX x. This function is not stack-clean.

long ZX_lval(GEN x, ulong p) as ZX_pval, except that p is an ulong (p > 1).

## Generic unary operators

Let op'' be a unary operation among

@3* neg: negation (-x).

@3* abs: absolute value (|x|).

@3* sqr: square (x^2).

@3The names and prototypes of the low-level functions corresponding to op are as follows. The result is of the same type as x.

@3GEN opi(GEN x) creates the result of op applied to the t_INT x.

@3GEN opr(GEN x) creates the result of op applied to the t_REAL x.

@3GEN mpop(GEN x) creates the result of op applied to the t_INT or t_REAL x.

@3Complete list of available functions:

GEN absi(GEN x), GEN absr(GEN x), GEN mpabs(GEN x)

GEN negi(GEN x), GEN negr(GEN x), GEN mpneg(GEN x)

GEN sqri(GEN x), GEN sqrr(GEN x), GEN mpsqr(GEN x)

GEN absi_shallow(GEN x) x being a t_INT, returns a shallow copy of |x|, in particular returns x itself when x >= 0, and negi(x) otherwise.

GEN mpabs_shallow(GEN x) x being a t_INT or a t_REAL, returns a shallow copy of |x|, in particular returns x itself when x >= 0, and mpneg(x) otherwise.

@3Some miscellaneous routines:

GEN sqrs(long x) returns x^2.

GEN sqru(ulong x) returns x^2.

## Comparison operators

long minss(long x, long y)

ulong minuu(ulong x, ulong y)

double mindd(double x, double y) returns the min of x and y.

long maxss(long x, long y)

ulong maxuu(ulong x, ulong y)

double maxdd(double x, double y) returns the max of x and y.

int mpcmp(GEN x, GEN y) compares the t_INT or t_REAL x to the t_INT or t_REAL y. The result is the sign of x-y.

int cmpii(GEN x, GEN y) compares the t_INT x to the t_INT y.

int cmpir(GEN x, GEN y) compares the t_INT x to the t_REAL y.

int cmpis(GEN x, long s) compares the t_INT x to the long s.

int cmpsi(long s, GEN x) compares the long s to the t_INT x.

int cmpsr(long s, GEN x) compares the long s to the t_REAL x.

int cmpri(GEN x, GEN y) compares the t_REAL x to the t_INT y.

int cmprr(GEN x, GEN y) compares the t_REAL x to the t_REAL y.

int cmprs(GEN x, long s) compares the t_REAL x to the long s.

int equalii(GEN x, GEN y) compares the t_INTs x and y. The result is 1 if x = y, 0 otherwise.

int equalrr(GEN x, GEN y) compares the t_REALs x and y. The result is 1 if x = y, 0 otherwise. Equality is decided according to the following rules: all real zeroes are equal, and different from a non-zero real; two non-zero reals are equal if all their digits coincide up to the length of the shortest of the two, and the remaining words in the mantissa of the longest are all 0.

int equalsi(long s, GEN x)

int equalis(GEN x, long s) compare the t_INT x and the long s. The result is 1 if x = y, 0 otherwise.

The remaining comparison operators disregard the sign of their operands

int absequaliu(GEN x, ulong u) compare the absolute value of the t_INT x and the ulong s. The result is 1 if |x |= y, 0 otherwise. This is marginally more efficient than equalis even when x is known to be non-negative.

int absequalui(ulong u, GEN x)

int abscmpiu(GEN x, ulong u) compare the absolute value of the t_INT x and the ulong u.

int abscmpui(ulong u, GEN x)

int abscmpii(GEN x, GEN y) compares the t_INTs x and y. The result is the sign of |x| - |y|.

int absequalii(GEN x, GEN y) compares the t_INTs x and y. The result is 1 if |x |= |y|, 0 otherwise.

int abscmprr(GEN x, GEN y) compares the t_REALs x and y. The result is the sign of |x| - |y|.

int absrnz_equal2n(GEN x) tests whether a non-zero t_REAL x is equal to +- 2^e for some integer e.

int absrnz_equal1(GEN x) tests whether a non-zero t_REAL x is equal to +- 1.

## Generic binary operators

The operators in this section have arguments of C-type GEN, long, and ulong, and only t_INT and t_REAL GENs are allowed. We say an argument is a real type if it is a t_REAL GEN, and an integer type otherwise. The result is always a t_REAL unless both x and y are integer types.

Let op'' be a binary operation among

@3* add: addition (x + y).

@3* sub: subtraction (x - y).

@3* mul: multiplication (x * y).

@3* div: division (x / y). In the case where x and y are both integer types, the result is the Euclidean quotient, where the remainder has the same sign as the dividend x. It is the ordinary division otherwise. A division-by-0 error occurs if y is equal to 0.

The last two generic operations are defined only when arguments have integer types; and the result is a t_INT:

@3* rem: remainder (x % y''). The result is the Euclidean remainder corresponding to div, i.e. its sign is that of the dividend x.

@3* mod: true remainder (x % y). The result is the true Euclidean remainder, i.e. non-negative and less than the absolute value of y.

@3Important technical note. The rules given above fixing the output type (to t_REAL unless both inputs are integer types) are subtly incompatible with the general rules obeyed by PARI's generic functions, such as gmul or gdiv for instance: the latter return a result containing as much information as could be deduced from the inputs, so it is not true that if x is a t_INT and y a t_REAL, then gmul(x,y) is always the same as mulir(x,y). The exception is x = 0, in that case we can deduce that the result is an exact 0, so gmul returns gen_0, while mulir returns a t_REAL 0. Specifically, the one resulting from the conversion of gen_0 to a t_REAL of precision precision(y), multiplied by y; this determines the exponent of the real 0 we obtain.

The reason for the discrepancy between the two rules is that we use the two sets of functions in different contexts: generic functions allow to write high-level code forgetting about types, letting PARI return results which are sensible and as simple as possible; type specific functions are used in kernel programming, where we do care about types and need to maintain strict consistency: it is much easier to compute the types of results when they are determined from the types of the inputs only (without taking into account further arithmetic properties, like being non-0).

The names and prototypes of the low-level functions corresponding to op are as follows. In this section, the z argument in the z-functions must be of type t_INT when no r or mp appears in the argument code (no t_REAL operand is involved, only integer types), and of type t_REAL otherwise.

@3GEN mpop[z](GEN x, GEN y[, GEN z]) applies op to the t_INT or t_REAL x and y. The function mpdivz does not exist (its semantic would change drastically depending on the type of the z argument), and neither do mprem[z] nor mpmod[z] (specific to integers).

@3GEN opsi[z](long s, GEN x[, GEN z]) applies op to the long s and the t_INT x. These functions always return the global constant gen_0 (not a copy) when the sign of the result is 0.

@3GEN opsr[z](long s, GEN x[, GEN z]) applies op to the long s and the t_REAL x.

@3GEN opss[z](long s, long t[, GEN z]) applies op to the longs s and t. These functions always return the global constant gen_0 (not a copy) when the sign of the result is 0.

@3GEN opii[z](GEN x, GEN y[, GEN z]) applies op to the t_INTs x and y. These functions always return the global constant gen_0 (not a copy) when the sign of the result is 0.

@3GEN opir[z](GEN x, GEN y[, GEN z]) applies op to the t_INT x and the t_REAL y.

@3GEN opis[z](GEN x, long s[, GEN z]) applies op to the t_INT x and the long s. These functions always return the global constant gen_0 (not a copy) when the sign of the result is 0.

@3GEN opri[z](GEN x, GEN y[, GEN z]) applies op to the t_REAL x and the t_INT y.

@3GEN oprr[z](GEN x, GEN y[, GEN z]) applies op to the t_REALs x and y.

@3GEN oprs[z](GEN x, long s[, GEN z]) applies op to the t_REAL x and the long s.

@3Some miscellaneous routines:

long expu(ulong x) assuming x > 0, returns the binary exponent of the real number equal to x. This is a special case of gexpo.

GEN adduu(ulong x, ulong y)

GEN addiu(GEN x, ulong y)

GEN addui(ulong x, GEN y) adds x and y.

GEN subuu(ulong x, ulong y)

GEN subiu(GEN x, ulong y)

GEN subui(ulong x, GEN y) subtracts x by y.

GEN muluu(ulong x, ulong y) multiplies x by y.

GEN mului(ulong x, GEN y) multiplies x by y.

GEN muluui(ulong x, ulong y, GEN z) return xyz.

GEN muliu(GEN x, ulong y) multiplies x by y.

void addumului(ulong a, ulong b, GEN x) return a + b|X|.

GEN addmuliu(GEN x, GEN y, ulong u) returns x +yu.

GEN addmulii(GEN x, GEN y, GEN z) returns x + yz.

GEN addmulii_inplace(GEN x, GEN y, GEN z) returns x + yz, but returns x itself and not a copy if yz = 0. Not suitable for gerepile or gerepileupto.

GEN addmuliu_inplace(GEN x, GEN y, ulong u) returns x +yu, but returns x itself and not a copy if yu = 0. Not suitable for gerepile or gerepileupto.

GEN submuliu_inplace(GEN x, GEN y, ulong u) returns x- yu, but returns x itself and not a copy if yu = 0. Not suitable for gerepile or gerepileupto.

GEN lincombii(GEN u, GEN v, GEN x, GEN y) returns ux + vy.

GEN mulsubii(GEN y, GEN z, GEN x) returns yz - x.

GEN submulii(GEN x, GEN y, GEN z) returns x - yz.

GEN submuliu(GEN x, GEN y, ulong u) returns x -yu.

GEN mulu_interval(ulong a, ulong b) returns a(a+1)...b, assuming that a <= b.

GEN muls_interval(long a, long b) returns a(a+1)...b, assuming that a <= b.

GEN invr(GEN x) returns the inverse of the non-zero t_REAL x.

GEN truedivii(GEN x, GEN y) returns the true Euclidean quotient (with non-negative remainder less than |y|).

GEN truedivis(GEN x, long y) returns the true Euclidean quotient (with non-negative remainder less than |y|).

GEN truedivsi(long x, GEN y) returns the true Euclidean quotient (with non-negative remainder less than |y|).

GEN centermodii(GEN x, GEN y, GEN y2), given t_INTs x, y, returns z congruent to x modulo y, such that -y/2 <= z < y/2. The function requires an extra argument y2, such that y2 = shifti(y, -1). (In most cases, y is constant for many reductions and y2 need only be computed once.)

GEN remi2n(GEN x, long n) returns x mod 2^n.

GEN addii_sign(GEN x, long sx, GEN y, long sy) add the t_INTs x and y as if their signs were sx and sy.

GEN addir_sign(GEN x, long sx, GEN y, long sy) add the t_INT x and the t_REAL y as if their signs were sx and sy.

GEN addrr_sign(GEN x, long sx, GEN y, long sy) add the t_REALs x and y as if their signs were sx and sy.

GEN addsi_sign(long x, GEN y, long sy) add x and the t_INT y as if its sign was sy.

GEN addui_sign(ulong x, GEN y, long sy) add x and the t_INT y as if its sign was sy.

## Exact division and divisibility

GEN diviiexact(GEN x, GEN y) returns the Euclidean quotient x / y, assuming y divides x. Uses Jebelean algorithm (Jebelean-Krandick bidirectional exact division is not implemented).

GEN diviuexact(GEN x, ulong y) returns the Euclidean quotient x / y, assuming y divides x and y is non-zero.

GEN diviuuexact(GEN x, ulong y, ulong z) returns the Euclidean quotient x/(yz), assuming yz divides x and yz != 0.

The following routines return 1 (true) if y divides x, and 0 otherwise. (Error if y is 0, even if x is 0.) All GEN are assumed to be t_INTs:

int dvdii(GEN x, GEN y), int dvdis(GEN x, long y), int dvdiu(GEN x, ulong y),

int dvdsi(long x, GEN y), int dvdui(ulong x, GEN y).

The following routines return 1 (true) if y divides x, and in that case assign the quotient to z; otherwise they return 0. All GEN are assumed to be t_INTs:

int dvdiiz(GEN x, GEN y, GEN z), int dvdisz(GEN x, long y, GEN z).

int dvdiuz(GEN x, ulong y, GEN z) if y divides x, assigns the quotient |x|/y to z and returns 1 (true), otherwise returns 0 (false).

## Division with integral operands and t_REAL result

GEN rdivii(GEN x, GEN y, long prec), assuming x and y are both of type t_INT, return the quotient x/y as a t_REAL of precision prec.

GEN rdiviiz(GEN x, GEN y, GEN z), assuming x and y are both of type t_INT, and z is a t_REAL, assign the quotient x/y to z.

GEN rdivis(GEN x, long y, long prec), assuming x is of type t_INT, return the quotient x/y as a t_REAL of precision prec.

GEN rdivsi(long x, GEN y, long prec), assuming y is of type t_INT, return the quotient x/y as a t_REAL of precision prec.

GEN rdivss(long x, long y, long prec), return the quotient x/y as a t_REAL of precision prec.

## Division with remainder

The following functions return two objects, unless specifically asked for only one of them --- a quotient and a remainder. The quotient is returned and the remainder is returned through the variable whose address is passed as the r argument. The term true Euclidean remainder refers to the non-negative one (mod), and Euclidean remainder by itself to the one with the same sign as the dividend (rem). All GENs, whether returned directly or through a pointer, are created on the stack.

GEN dvmdii(GEN x, GEN y, GEN *r) returns the Euclidean quotient of the t_INT x by a t_INT y and puts the remainder into *r. If r is equal to NULL, the remainder is not created, and if r is equal to ONLY_REM, only the remainder is created and returned. In the generic case, the remainder is created after the quotient and can be disposed of individually with a cgiv(r). The remainder is always of the sign of the dividend x. If the remainder is 0 set r = gen_0.

void dvmdiiz(GEN x, GEN y, GEN z, GEN t) assigns the Euclidean quotient of the t_INTs x and y into the t_INT z, and the Euclidean remainder into the t_INT t.

@3Analogous routines dvmdis[z], dvmdsi[z], dvmdss[z] are available, where s denotes a long argument. But the following routines are in general more flexible:

long sdivss_rem(long s, long t, long *r) computes the Euclidean quotient and remainder of the longs s and t. Puts the remainder into *r, and returns the quotient. The remainder is of the sign of the dividend s, and has strictly smaller absolute value than t.

long sdivsi_rem(long s, GEN x, long *r) computes the Euclidean quotient and remainder of the long s by the t_INT x. As sdivss_rem otherwise.

long sdivsi(long s, GEN x) as sdivsi_rem, without remainder.

GEN divis_rem(GEN x, long s, long *r) computes the Euclidean quotient and remainder of the t_INT x by the long s. As sdivss_rem otherwise.

GEN diviu_rem(GEN x, ulong s, ulong *r) computes the Euclidean quotient and remainder of absolute value of the t_INT x by the ulong s. As sdivss_rem otherwise.

ulong udiviu_rem(GEN n, ulong d, ulong *r) as diviu_rem, assuming that |n|/d fits into an ulong.

ulong udivui_rem(ulong x, GEN y, ulong *rem) computes the Euclidean quotient and remainder of x by y. As sdivss_rem otherwise.

ulong udivuu_rem(ulong x, ulong y, ulong *rem) computes the Euclidean quotient and remainder of x by y. As sdivss_rem otherwise.

ulong ceildivuu(ulong x, ulong y) return the ceiling of x / y.

GEN divsi_rem(long s, GEN y, long *r) computes the Euclidean quotient and remainder of the long s by the GEN y. As sdivss_rem otherwise.

GEN divss_rem(long x, long y, long *r) computes the Euclidean quotient and remainder of the long x by the long y. As sdivss_rem otherwise.

GEN truedvmdii(GEN x, GEN y, GEN *r), as dvmdii but with a non-negative remainder.

GEN truedvmdis(GEN x, long y, GEN *z), as dvmdis but with a non-negative remainder.

GEN truedvmdsi(long x, GEN y, GEN *z), as dvmdsi but with a non-negative remainder.

## Modulo to longs

The following variants of modii do not clutter the stack:

long smodis(GEN x, long y) computes the true Euclidean remainder of the t_INT x by the long y. This is the non-negative remainder, not the one whose sign is the sign of x as in the div functions.

long smodss(long x, long y) computes the true Euclidean remainder of the long x by a long y.

ulong umodsu(long x, ulong y) computes the true Euclidean remainder of the long x by a ulong y.

ulong umodiu(GEN x, ulong y) computes the true Euclidean remainder of the t_INT x by the ulong y.

ulong umodui(ulong x, GEN y) computes the true Euclidean remainder of the ulong x by the t_INT |y|.

The routine smodsi does not exist, since it would not always be defined: for a negative x, if the quotient is +-1, the result x + |y| would in general not fit into a long. Use either umodui or modsi.

These functions directly access the binary data and are thus much faster than the generic modulo functions:

int mpodd(GEN x) which is 1 if x is odd, and 0 otherwise.

ulong Mod2(GEN x)

ulong Mod4(GEN x)

ulong Mod8(GEN x)

ulong Mod16(GEN x)

ulong Mod32(GEN x)

ulong Mod64(GEN x) give the residue class of x modulo the corresponding power of 2.

ulong umodi2n(GEN x, long n) give the residue class of x modulo 2^n, 0 <= n < BITS_IN_LONG.

The following functions assume that x != 0 and in fact disregard the sign of x. There are about 10% faster than the safer variants above:

long mod2(GEN x)

long mod4(GEN x)

long mod8(GEN x)

long mod16(GEN x)

long mod32(GEN x)

long mod64(GEN x) give the residue class of |x| modulo the corresponding power of 2, for non-zero x. As well,

ulong mod2BIL(GEN x) returns the least significant word of |x|, still assuming that x != 0.

## Powering, Square root

GEN powii(GEN x, GEN n), assumes x and n are t_INTs and returns x^n.

GEN powuu(ulong x, ulong n), returns x^n.

GEN powiu(GEN x, ulong n), assumes x is a t_INT and returns x^n.

GEN powis(GEN x, long n), assumes x is a t_INT and returns x^n (possibly a t_FRAC if n < 0).

GEN powrs(GEN x, long n), assumes x is a t_REAL and returns x^n. This is considered as a sequence of mulrr, possibly empty: as such the result has type t_REAL, even if n = 0. Note that the generic function gpowgs(x,0) would return gen_1, see the technical note in "Label se:genbinop".

GEN powru(GEN x, ulong n), assumes x is a t_REAL and returns x^n (always a t_REAL, even if n = 0).

GEN powersr(GEN e, long n). Given a t_REAL e, return the vector v of all e^i, 0 <= i <= n, where v[i] = e^{i-1}.

GEN powrshalf(GEN x, long n), assumes x is a t_REAL and returns x^{n/2} (always a t_REAL, even if n = 0).

GEN powruhalf(GEN x, ulong n), assumes x is a t_REAL and returns x^{n/2} (always a t_REAL, even if n = 0).

GEN powrfrac(GEN x, long n, long d), assumes x is a t_REAL and returns x^{n/d} (always a t_REAL, even if n = 0).

GEN powIs(long n) returns I^n\in{1,I,-1,-I} (t_INT for even n, t_COMPLEX otherwise).

ulong upowuu(ulong x, ulong n), returns x^n when  < 2^BIL, and 0 otherwise (overflow).

GEN sqrtremi(GEN N, GEN *r), returns the integer square root S of the non-negative t_INT N (rounded towards 0) and puts the remainder R into *r. Precisely, N = S^2 + R with 0 <= R <= 2S. If r is equal to NULL, the remainder is not created. In the generic case, the remainder is created after the quotient and can be disposed of individually with cgiv(R). If the remainder is 0 set R = gen_0.

Uses a divide and conquer algorithm (discrete variant of Newton iteration) due to Paul Zimmermann (Karatsuba Square Root'', INRIA Research Report 3805 (1999)).

GEN sqrti(GEN N), returns the integer square root S of the non-negative t_INT N (rounded towards 0). This is identical to sqrtremi(N, NULL).

long logintall(GEN B, GEN y, GEN *ptq) returns the floor e of log _y B, where B > 0 and y > 1 are integers. If ptq is not NULL, set it to y^e. (Analogous to logint0, whithout sanity checks.)

long logint(GEN B, GEN y) returns the floor e of log _y B, where B > 0 and y > 1 are integers.

## GCD, extended GCD and LCM

long cgcd(long x, long y) returns the GCD of x and y.

ulong ugcd(ulong x, ulong y) returns the GCD of x and y.

long clcm(long x, long y) returns the LCM of x and y, provided it fits into a long. Silently overflows otherwise.

GEN gcdii(GEN x, GEN y), returns the GCD of the t_INTs x and y.

GEN lcmii(GEN x, GEN y), returns the LCM of the t_INTs x and y.

GEN bezout(GEN a,GEN b, GEN *u,GEN *v), returns the GCD d of t_INTs a and b and sets u, v to the Bezout coefficients such that au + bv = d.

long cbezout(long a,long b, long *u,long *v), returns the GCD d of a and b and sets u, v to the Bezout coefficients such that au + bv = d.

GEN ZV_extgcd(GEN A) given a vector of n integers A, returns [d, U], where d is the GCD of the A[i] and U is a matrix in GL_n(Z) such that AU = [0,...,0,D].

## Continued fractions and convergents

GEN ZV_allpnqn(GEN x) given x = [a_0, ..., a_n] a continued fraction from gboundcf, n >= 0, return all convergents as [P,Q], where P = [p_0,...,p_n] and Q = [q_0,...,q_n].

## Pseudo-random integers

These routine return pseudo-random integers uniformly distributed in some interval. The all use the same underlying generator which can be seeded and restarted using getrand and setrand.

void setrand(GEN seed) reseeds the random number generator using the seed n. The seed is either a technical array output by getrand or a small positive integer, used to generate deterministically a suitable state array. For instance, running a randomized computation starting by setrand(1) twice will generate the exact same output.

GEN getrand(void) returns the current value of the seed used by the pseudo-random number generator random. Useful mainly for debugging purposes, to reproduce a specific chain of computations. The returned value is technical (reproduces an internal state array of type t_VECSMALL), and can only be used as an argument to setrand.

ulong pari_rand(void) returns a random 0 <= x < 2^BIL.

long random_bits(long k) returns a random 0 <= x < 2^k. Assumes that 0 <= k <= BIL.

ulong random_Fl(ulong p) returns a pseudo-random integer in 0, 1,...p-1.

GEN randomi(GEN n) returns a random t_INT between 0 and n - 1.

GEN randomr(long prec) returns a random t_REAL in [0,1[, with precision prec.

## Modular operations

In this subsection, all GENs are t_INT.

GEN Fp_red(GEN a, GEN m) returns a modulo m (smallest non-negative residue). (This is identical to modii).

GEN Fp_neg(GEN a, GEN m) returns -a modulo m (smallest non-negative residue).

GEN Fp_add(GEN a, GEN b, GEN m) returns the sum of a and b modulo m (smallest non-negative residue).

GEN Fp_sub(GEN a, GEN b, GEN m) returns the difference of a and b modulo m (smallest non-negative residue).

GEN Fp_center(GEN a, GEN p, GEN pov2) assuming that pov2 is shifti(p,-1) and that a is between 0 and p - 1 and, returns the representative of a in the symmetric residue system.

GEN Fp_mul(GEN a, GEN b, GEN m) returns the product of a by b modulo m (smallest non-negative residue).

GEN Fp_addmul(GEN x, GEN y, GEN z, GEN p) returns x + yz.

GEN Fp_mulu(GEN a, ulong b, GEN m) returns the product of a by b modulo m (smallest non-negative residue).

GEN Fp_muls(GEN a, long b, GEN m) returns the product of a by b modulo m (smallest non-negative residue).

GEN Fp_halve(GEN x, GEN m) returns z such that 2 z = x modulo m assuming such z exists.

GEN Fp_sqr(GEN a, GEN m) returns a^2 modulo m (smallest non-negative residue).

ulong Fp_powu(GEN x, ulong n, GEN m) raises x to the n-th power modulo m (smallest non-negative residue). Not memory-clean, but suitable for gerepileupto.

ulong Fp_pows(GEN x, long n, GEN m) raises x to the n-th power modulo m (smallest non-negative residue). A negative n is allowed Not memory-clean, but suitable for gerepileupto.

GEN Fp_pow(GEN x, GEN n, GEN m) returns x^n modulo m (smallest non-negative residue).

GEN Fp_powers(GEN x, long n, GEN m) returns [x^0,..., x^n] modulo m as a t_VEC (smallest non-negative residue).

GEN Fp_inv(GEN a, GEN m) returns an inverse of a modulo m (smallest non-negative residue). Raise an error if a is not invertible.

GEN Fp_invsafe(GEN a, GEN m) as Fp_inv, but return NULL if a is not invertible.

GEN FpV_inv(GEN x, GEN m) x being a vector of t_INTs, return the vector of inverses of the x[i] mod m. The routine uses Montgomery's trick, and involves a single inversion mod m, plus 3(N-1) multiplications for N entries. The routine is not stack-clean: 2N integers mod m are left on stack, besides the N in the result.

GEN Fp_div(GEN a, GEN b, GEN m) returns the quotient of a by b modulo m (smallest non-negative residue). Raise an error if b is not invertible.

int invmod(GEN a, GEN m, GEN *g), return 1 if a modulo m is invertible, else return 0 and set g =  gcd (a,m).

In the following three functions the integer parameter ord can be given either as a positive t_INT N, or as its factorization matrix faN, or as a pair [N,faN]. The parameter may be omitted by setting it to NULL (the value is then p-1).

GEN Fp_log(GEN a, GEN g, GEN ord, GEN p) Let g such that g^{ord} = 1 (mod p). Return an integer e such that a^e = g (mod p). If e does not exist, the result is undefined.

GEN Fp_order(GEN a, GEN ord, GEN p) returns the order of the Fp a. Assume that ord is a multiple of the order of a.

GEN Fp_factored_order(GEN a, GEN ord, GEN p) returns [o,F], where o is the multiplicative order of the Fp a in F_p^*, and F is the factorization of o. Assume that ord is a multiple of the order of a.

int Fp_issquare(GEN x, GEN p) returns 1 if x is a square modulo p, and 0 otherwise.

int Fp_ispower(GEN x, GEN n, GEN p) returns 1 if x is an n-th power modulo p, and 0 otherwise.

GEN Fp_sqrt(GEN x, GEN p) returns a square root of x modulo p (the smallest non-negative residue), where x, p are t_INTs, and p is assumed to be prime. Return NULL if x is not a quadratic residue modulo p.

GEN Fp_sqrtn(GEN a, GEN n, GEN p, GEN *zn) returns NULL if a is not an n-th power residue mod p. Otherwise, returns an n-th root of a; if zn is non-NULL set it to a primitive m-th root of 1, m =  gcd (p-1,n) allowing to compute all m solutions in F_p of the equation x^n = a.

GEN Zn_sqrt(GEN x, GEN n) returns one of the square roots of x modulo n (possibly not prime), where x is a t_INT and n is either a t_INT or is given by its factorisation matrix. Return NULL if no such square root exist.

long kross(long x, long y) returns the Kronecker symbol (x|y), i.e.-1, 0 or 1. If y is an odd prime, this is the Legendre symbol. (Contrary to krouu, kross also supports y = 0)

long krouu(ulong x, ulong y) returns the Kronecker symbol (x|y), i.e. -1, 0 or 1. Assumes y is non-zero. If y is an odd prime, this is the Legendre symbol.

long krois(GEN x, long y) returns the Kronecker symbol (x|y) of t_INT x and long y. As kross otherwise.

long kroiu(GEN x, ulong y) returns the Kronecker symbol (x|y) of t_INT x and non-zero ulong y. As krouu otherwise.

long krosi(long x, GEN y) returns the Kronecker symbol (x|y) of long x and t_INT y. As kross otherwise.

long kroui(ulong x, GEN y) returns the Kronecker symbol (x|y) of long x and t_INT y. As kross otherwise.

long kronecker(GEN x, GEN y) returns the Kronecker symbol (x|y) of t_INTs x and y. As kross otherwise.

GEN pgener_Fp(GEN p) returns the smallest primitive root modulo p, assuming p is prime.

GEN pgener_Zp(GEN p) returns the smallest primitive root modulo p^k, k > 1, assuming p is an odd prime.

long Zp_issquare(GEN x, GEN p) returns 1 if the t_INT x is a p-adic square, 0 otherwise.

long Zn_issquare(GEN x, GEN n) returns 1 if t_INT x is a square modulo n (possibly not prime), where n is either a t_INT or is given by its factorisation matrix. Return 0 otherwise.

long Zn_ispower(GEN x, GEN n, GEN K, GEN *py) returns 1 if t_INT x is a K-th power modulo n (possibly not prime), where n is either a t_INT or is given by its factorisation matrix. Return 0 otherwise. If py is not NULL, set it to y such that y^K = x modulo n.

GEN pgener_Fp_local(GEN p, GEN L), L being a vector of primes dividing p - 1, returns the smallest integer x > 1 which is a generator of the ell-Sylow of F_p^* for every ell in L. In other words, x^{(p-1)/ell} != 1 for all such ell. In particular, returns pgener_Fp(p) if L contains all primes dividing p - 1. It is not necessary, and in fact slightly inefficient, to include ell = 2, since 2 is treated separately in any case, i.e. the generator obtained is never a square.

GEN rootsof1_Fp(GEN n, GEN p) returns a primitive n-th root modulo the prime p.

GEN rootsof1u_Fp(ulong n, GEN p) returns a primitive n-th root modulo the prime p.

ulong rootsof1_Fl(ulong n, ulong p) returns a primitive n-th root modulo the prime p.

## Extending functions to vector inputs

The following functions apply f to the given arguments, recursively if they are of vector / matrix type:

GEN map_proto_G(GEN (*f)(GEN), GEN x) For instance, if x is a t_VEC, return a t_VEC whose components are the f(x[i]).

GEN map_proto_lG(long (*f)(GEN), GEN x) As above, applying the function stoi( f() ).

GEN map_proto_GL(GEN (*f)(GEN,long), GEN x, long y)

GEN map_proto_lGL(long (*f)(GEN,long), GEN x, long y)

In the last function, f implements an associative binary operator, which we extend naturally to an n-ary operator f_n for any n: by convention, f_0() = 1, f_1(x) = x, and

 f_n(x_1,...,x_n) = f( f_{n-1}(x_1,...,x_{n-1}), x_n)),

for n >= 2.

GEN gassoc_proto(GEN (*f)(GEN,GEN),GEN x, GEN y) If y is not NULL, return f(x,y). Otherwise, x must be of vector type, and we return the result of f applied to its components, computed using a divide-and-conquer algorithm. More precisely, return

f( f(x_1,NULL), f(x_2,NULL) ),

where x_1, x_2 are the two halves of x.

## Miscellaneous arithmetic functions

long bigomegau(ulong n) returns the number of prime divisors of n > 0, counted with multiplicity.

ulong coreu(ulong n), unique squarefree integer d dividing n such that n/d is a square.

ulong corediscs(long d, ulong *pt_f), d (possibly negative) being congruent to 0 or 1 modulo 4, return the fundamental discriminant D such that d = D*f^2 and set *pt_f to f (if *pt_f not NULL).

ulong eulerphiu(ulong n), Euler's totient function of n.

ulong eulerphiu_fact(GEN fa), Euler's totient function of the ulong n, where fa is factoru(n).

long moebiusu(ulong n), Moebius mu-function of n.

GEN divisorsu(ulong n), returns the divisors of n in a t_VECSMALL, sorted by increasing order.

ulong divisorsu_fact(GEN fa), as divisorsu(n) where fa is factoru(n).

long omegau(ulong n) returns the number of prime divisors of n > 0.

long uissquarefree(ulong n) returns 1 if n is square-free, and 0 otherwise.

ulong uissquarefree_fact(GEN fa) returns uissquarefree(n), where fa is factoru(n).

long uposisfundamental(ulong x) return 1 if x is a fundamental discriminant, and 0 otherwise.

long unegisfundamental(ulong x) return 1 if -x is a fundamental discriminant, and 0 otherwise.

long sisfundamental(long x) return 1 if x is a fundamental discriminant, and 0 otherwise.

int uis_357_power(ulong x, ulong *pt, ulong *mask) as is_357_power for ulong x.

int uis_357_powermod(ulong x, ulong *mask) as uis_357_power, but only check for 3rd, 5th or 7th powers modulo 211 x 209 x 61 x 203 x 117 x 31 x 43 x 71.

long uisprimepower(ulong n, ulong *p) as isprimepower, for ulong n.

int uislucaspsp(ulong n) returns 1 if the ulong n fails Lucas compositeness test (it thus may be prime or composite), and 0 otherwise (proving that n is composite).

ulong sumdigitsu(ulong n) returns the sum of decimal digits of u.

GEN usumdivkvec(ulong n, GEN K) K being a t_VECSMALL of positive integers. Returns the vector of sumdivk(n, K[i]).

GEN usumdiv_fact(GEN fa), sum of divisors of ulong n, where fa is factoru(n).

GEN usumdivk_fact(GEN fa, ulong k), sum of k-th powers of divisors of ulong n, where fa is factoru(n).

GEN hilbertii(GEN x, GEN y, GEN p), returns the Hilbert symbol (x,y) at the prime p (NULL for the place at infinity); x and y are t_INTs.

GEN sumdedekind(GEN h, GEN k) returns the Dedekind sum attached to the t_INT h and k, k > 0.

GEN sumdedekind_coprime(GEN h, GEN k) as sumdedekind, except that h and k are assumed to be coprime t_INTs.

GEN u_sumdedekind_coprime(long h, long k) Let k > 0, 0 <= h < k, (h,k) = 1. Returns [s_1,s_2] in a t_VECSMALL, such that s(h,k) = (s_2 + k s_1) / (12k). Requires max (h + k/2, k) < LONG_MAX to avoid overflow, in particular k <= (2/3)LONG_MAX is fine.

\newpage

# NAME

libPARI - Level 2 kernel

These functions deal with modular arithmetic, linear algebra and polynomials where assumptions can be made about the types of the coefficients.

# Naming scheme

A function name is built in the following way: A_1_..._A_nfun for an operation fun with n arguments of class A_1,..., A_n. A class name is given by a base ring followed by a number of code letters. Base rings are among

Fl: Z/lZ where l < 2^{BIL} is not necessarily prime. Implemented using ulongs

Fp: Z/pZ where p is a t_INT, not necessarily prime. Implemented as t_INTs z, preferably satisfying 0 <= z < p. More precisely, any t_INT can be used as an Fp, but reduced inputs are treated more efficiently. Outputs from Fpxxx routines are reduced.

Fq: Z[X]/(p,T(X)), p a t_INT, T a t_POL with Fp coefficients or NULL (in which case no reduction modulo T is performed). Implemented as t_POLs z with Fp coefficients, deg (z) <  deg  T, although z a t_INT is allowed for elements in the prime field.

Z: the integers Z, implemented as t_INTs.

Zp: the p-adic integers Z_p, implemented as t_INTs, for arbitrary p

Zl: the p-adic integers Z_p, implemented as t_INTs, for p < 2^{BIL}

z: the integers Z, implemented using (signed) longs.

Q: the rational numbers Q, implemented as t_INTs and t_FRACs.

Rg: a commutative ring, whose elements can be gadd-ed, gmul-ed, etc.

@3Possible letters are:

X: polynomial in X (t_POL in a fixed variable), e.g. FpX means Z/pZ[X]

Y: polynomial in Y != X. This is used to resolve ambiguities. E.g. FpXY means ((Z/pZ)[X])[Y].

V: vector (t_VEC or t_COL), treated as a line vector (independently of the actual type). E.g. ZV means Z^k for some k.

C: vector (t_VEC or t_COL), treated as a column vector (independently of the actual type). The difference with V is purely semantic: if the result is a vector, it will be of type t_COL unless mentioned otherwise. For instance the function ZC_add receives two integral vectors (t_COL or t_VEC, possibly different types) of the same length and returns a t_COL whose entries are the sums of the input coefficients.

M: matrix (t_MAT). E.g. QM means a matrix with rational entries

T: Trees. Either a leaf or a t_VEC of trees.

E: point over an elliptic curve, represented as two-component vectors [x,y], except for the represented by the one-component vector [0]. Not all curve models are supported.

Q: representative (t_POL) of a class in a polynomial quotient ring. E.g. an FpXQ belongs to (Z/pZ)[X]/(T(X)), FpXQV means a vector of such elements, etc.

n: a polynomial representative (t_POL) for a truncated power series modulo X^n. E.g. an FpXn belongs to (Z/pZ)[X]/(X^n), FpXnV means a vector of such elements, etc.

x, y, m, v, c, q: as their uppercase counterpart, but coefficient arrays are implemented using t_VECSMALLs, which coefficient understood as ulongs.

x and y (and q) are implemented by a t_VECSMALL whose first coefficient is used as a code-word and the following are the coefficients , similarly to a t_POL. This is known as a 'POLSMALL'.

m are implemented by a t_MAT whose components (columns) are t_VECSMALLs. This is known as a 'MATSMALL'.

v and c are regular t_VECSMALLs. Difference between the two is purely semantic.

@3Omitting the letter means the argument is a scalar in the base ring. Standard functions fun are

add: add

sub: subtract

mul: multiply

sqr: square

div: divide (Euclidean quotient)

rem: Euclidean remainder

divrem: return Euclidean quotient, store remainder in a pointer argument. Three special values of that pointer argument modify the default behavior: NULL (do not store the remainder, used to implement div), ONLY_REM (return the remainder, used to implement rem), ONLY_DIVIDES (return the quotient if the division is exact, and NULL otherwise).

gcd: GCD

extgcd: return GCD, store Bezout coefficients in pointer arguments

pow: exponentiate

eval: evaluation / composition

# Modular arithmetic

@3These routines implement univariate polynomial arithmetic and linear algebra over finite fields, in fact over finite rings of the form (Z/pZ)[X]/(T), where p is not necessarily prime and T\in(Z/pZ)[X] is possibly reducible; and finite extensions thereof. All this can be emulated with t_INTMOD and t_POLMOD coefficients and using generic routines, at a considerable loss of efficiency. Also, specialized routines are available that have no obvious generic equivalent.

## FpC / FpV, FpM

A ZV (resp. a ZM) is a t_VEC or t_COL (resp. t_MAT) with t_INT coefficients. An FpV or FpM, with respect to a given t_INT p, is the same with Fp coordinates; operations are understood over Z/pZ.

### Conversions

int Rg_is_Fp(GEN z, GEN *p), checks if z can be mapped to Z/pZ: a t_INT or a t_INTMOD whose modulus is equal to *p, (if *p not NULL), in that case return 1, else 0. If a modulus is found it is put in *p, else *p is left unchanged.

int RgV_is_FpV(GEN z, GEN *p), z a t_VEC (resp. t_COL), checks if it can be mapped to a FpV (resp. FpC), by checking Rg_is_Fp coefficientwise.

int RgM_is_FpM(GEN z, GEN *p), z a t_MAT, checks if it can be mapped to a FpM, by checking RgV_is_FpV columnwise.

GEN Rg_to_Fp(GEN z, GEN p), z a scalar which can be mapped to Z/pZ: a t_INT, a t_INTMOD whose modulus is divisible by p, a t_FRAC whose denominator is coprime to p, or a t_PADIC with underlying prime ell satisfying p = ell^n for some n (less than the accuracy of the input). Returns lift(z * Mod(1,p)), normalized.

GEN padic_to_Fp(GEN x, GEN p) special case of Rg_to_Fp, for a x a t_PADIC.

GEN RgV_to_FpV(GEN z, GEN p), z a t_VEC or t_COL, returns the FpV (as a t_VEC) obtained by applying Rg_to_Fp coefficientwise.

GEN RgC_to_FpC(GEN z, GEN p), z a t_VEC or t_COL, returns the FpC (as a t_COL) obtained by applying Rg_to_Fp coefficientwise.

GEN RgM_to_FpM(GEN z, GEN p), z a t_MAT, returns the FpM obtained by applying RgC_to_FpC columnwise.

GEN RgM_Fp_init(GEN z, GEN p, ulong *pp), given an RgM z, whose entries can be mapped to F_p (as per Rg_to_Fp), and a prime number p. This routine returns a normal form of z: either an F2m (p = 2), an Flm (p fits into an ulong) or an FpM. In the first two cases, pp is set to itou(p), and to 0 in the last.

The functions above are generally used as follow:

  GEN add(GEN x, GEN y)
{
GEN p = NULL;
if (Rg_is_Fp(x, &p) && Rg_is_Fp(y, &p) && p)
{
x = Rg_to_Fp(x, p); y = Rg_to_Fp(y, p);
return Fp_to_mod(z);
}
}

GEN FpC_red(GEN z, GEN p), z a ZC. Returns lift(Col(z) * Mod(1,p)), hence a t_COL.

GEN FpV_red(GEN z, GEN p), z a ZV. Returns lift(Vec(z) * Mod(1,p)), hence a t_VEC

GEN FpM_red(GEN z, GEN p), z a ZM. Returns lift(z * Mod(1,p)), which is an FpM.

### Basic operations

GEN FpC_center(GEN z, GEN p, GEN pov2) returns a t_COL whose entries are the Fp_center of the gel(z,i).

GEN FpM_center(GEN z, GEN p, GEN pov2) returns a matrix whose entries are the Fp_center of the gcoeff(z,i,j).

void FpC_center_inplace(GEN z, GEN p, GEN pov2) in-place version of FpC_center, using affii.

void FpM_center_inplace(GEN z, GEN p, GEN pov2) in-place version of FpM_center, using affii.

GEN FpC_add(GEN x, GEN y, GEN p) adds the ZC x and y and reduce modulo p to obtain an FpC.

GEN FpV_add(GEN x, GEN y, GEN p) same as FpC_add, returning and FpV.

GEN FpM_add(GEN x, GEN y, GEN p) adds the two ZMs x and y (assumed to have compatible dimensions), and reduce modulo p to obtain an FpM.

GEN FpC_sub(GEN x, GEN y, GEN p) subtracts the ZC y to the ZC x and reduce modulo p to obtain an FpC.

GEN FpV_sub(GEN x, GEN y, GEN p) same as FpC_sub, returning and FpV.

GEN FpM_sub(GEN x, GEN y, GEN p) subtracts the two ZMs x and y (assumed to have compatible dimensions), and reduce modulo p to obtain an FpM.

GEN FpC_Fp_mul(GEN x, GEN y, GEN p) multiplies the ZC x (seen as a column vector) by the t_INT y and reduce modulo p to obtain an FpC.

GEN FpM_Fp_mul(GEN x, GEN y, GEN p) multiplies the ZM x (seen as a column vector) by the t_INT y and reduce modulo p to obtain an FpM.

GEN FpC_FpV_mul(GEN x, GEN y, GEN p) multiplies the ZC x (seen as a column vector) by the ZV y (seen as a row vector, assumed to have compatible dimensions), and reduce modulo p to obtain an FpM.

GEN FpM_mul(GEN x, GEN y, GEN p) multiplies the two ZMs x and y (assumed to have compatible dimensions), and reduce modulo p to obtain an FpM.

GEN FpM_powu(GEN x, ulong n, GEN p) computes x^n where x is a square FpM.

GEN FpM_FpC_mul(GEN x, GEN y, GEN p) multiplies the ZM x by the ZC y (seen as a column vector, assumed to have compatible dimensions), and reduce modulo p to obtain an FpC.

GEN FpM_FpC_mul_FpX(GEN x, GEN y, GEN p, long v) is a memory-clean version of

    GEN tmp = FpM_FpC_mul(x,y,p);
return RgV_to_RgX(tmp, v);

GEN FpV_FpC_mul(GEN x, GEN y, GEN p) multiplies the ZV x (seen as a row vector) by the ZC y (seen as a column vector, assumed to have compatible dimensions), and reduce modulo p to obtain an Fp.

GEN FpV_dotproduct(GEN x,GEN y,GEN p) scalar product of x and y (assumed to have the same length).

GEN FpV_dotsquare(GEN x, GEN p) scalar product of x with itself. has t_INT entries.

GEN FpV_factorback(GEN L, GEN e, GEN p) given an FpV L and a ZV e of the same length, return prod_i L_i^{e_i} modulo p.

### Fp-linear algebra The implementations are not

asymptotically efficient (O(n^3) standard algorithms).

GEN FpM_deplin(GEN x, GEN p) returns a non-trivial kernel vector, or NULL if none exist.

GEN FpM_det(GEN x, GEN p) as det

GEN FpM_gauss(GEN a, GEN b, GEN p) as gauss, where b is a FpM.

GEN FpM_FpC_gauss(GEN a, GEN b, GEN p) as gauss, where b is a FpC.

GEN FpM_image(GEN x, GEN p) as image

GEN FpM_intersect(GEN x, GEN y, GEN p) as intersect

GEN FpM_inv(GEN x, GEN p) returns a left inverse of x (the inverse if x is square), or NULL if x is not invertible.

GEN FpM_FpC_invimage(GEN A, GEN y, GEN p) given an FpM A and an FpC y, returns an x such that Ax = y, or NULL if no such vector exist.

GEN FpM_invimage(GEN A, GEN y, GEN p) given two FpM A and y, returns x such that Ax = y, or NULL if no such matrix exist.

GEN FpM_ker(GEN x, GEN p) as ker

long FpM_rank(GEN x, GEN p) as rank

GEN FpM_indexrank(GEN x, GEN p) as indexrank

GEN FpM_suppl(GEN x, GEN p) as suppl

GEN FpM_hess(GEN x, GEN p) upper Hessenberg form of x over F_p.

GEN FpM_charpoly(GEN x, GEN p) characteristic polynomial of x.

### FqC, FqM and Fq-linear algebra

An FqM (resp. FqC) is a matrix (resp a t_COL) with Fq coefficients (with respect to given T, p), not necessarily reduced (i.e arbitrary t_INTs and ZXs in the same variable as T).

GEN FqC_add(GEN a, GEN b, GEN T, GEN p)

GEN FqC_sub(GEN a, GEN b, GEN T, GEN p)

GEN FqC_Fq_mul(GEN a, GEN b, GEN T, GEN p)

GEN FqM_deplin(GEN x, GEN T, GEN p) returns a non-trivial kernel vector, or NULL if none exist.

GEN FqM_gauss(GEN a, GEN b, GEN T, GEN p) as gauss, where b is a FqM.

GEN FqM_FqC_gauss(GEN a, GEN b, GEN T, GEN p) as gauss, where b is a FqC.

GEN FqM_FqC_mul(GEN a, GEN b, GEN T, GEN p)

GEN FqM_ker(GEN x, GEN T, GEN p) as ker

GEN FqM_image(GEN x, GEN T, GEN p) as image

GEN FqM_inv(GEN x, GEN T, GEN p) returns the inverse of x, or NULL if x is not invertible.

GEN FqM_mul(GEN a, GEN b, GEN T, GEN p)

long FqM_rank(GEN x, GEN T, GEN p) as rank

GEN FqM_suppl(GEN x, GEN T, GEN p) as suppl

GEN FqM_det(GEN x, GEN T, GEN p) as det

## Flc / Flv, Flm

See FpV, FpM operations.

GEN Flv_copy(GEN x) returns a copy of x.

GEN Flv_center(GEN z, ulong p, ulong ps2)

GEN Flm_copy(GEN x) returns a copy of x.

GEN matid_Flm(long n) returns an Flm which is an n x n identity matrix.

GEN scalar_Flm(long s, long n) returns an Flm which is s times the n x n identity matrix.

GEN Flm_center(GEN z, ulong p, ulong ps2)

GEN Flm_Fl_add(GEN x, ulong y, ulong p) returns x + y*Id (x must be square).

GEN Flm_Flc_mul(GEN x, GEN y, ulong p) multiplies x and y (assumed to have compatible dimensions).

GEN Flm_Flc_mul_pre(GEN x, GEN y, ulong p, ulong pi) multiplies x and y (assumed to have compatible dimensions), assuming pi is the pseudo inverse of p.

GEN Flm_Flc_mul_pre_Flx(GEN x, GEN y, ulong p, ulong pi, long sv) return Flv_to_Flx(Flm_Flc_mul_pre(x, y, p, pi), sv).

GEN Flm_Fl_mul(GEN x, ulong y, ulong p) multiplies the Flm x by y.

GEN Flm_neg(GEN x, ulong p) negates the Flm x.

void Flm_Fl_mul_inplace(GEN x, ulong y, ulong p) replaces the Flm x by x*y.

GEN Flv_Fl_mul(GEN x, ulong y, ulong p) multiplies the Flv x by y.

void Flv_Fl_mul_inplace(GEN x, ulong y, ulong p) replaces the Flc x by x*y.

void Flv_Fl_mul_part_inplace(GEN x, ulong y, ulong p, long l) multiplies x[1..l] by y modulo p. In place.

GEN Flv_Fl_div(GEN x, ulong y, ulong p) divides the Flv x by y.

void Flv_Fl_div_inplace(GEN x, ulong y, ulong p) replaces the Flv x by x/y.

void Flc_lincomb1_inplace(GEN X, GEN Y, ulong v, ulong q) sets X\leftarrow X + vY, where X,Y are Flc. Memory efficient (e.g. no-op if v = 0), and gerepile-safe.

GEN Flv_add(GEN x, GEN y, ulong p) adds two Flv.

void Flv_add_inplace(GEN x, GEN y, ulong p) replaces x by x+y.

GEN Flv_neg(GEN x, ulong p) returns -x.

void Flv_neg_inplace(GEN x, ulong p) replaces x by -x.

GEN Flv_sub(GEN x, GEN y, ulong p) subtracts y to x.

void Flv_sub_inplace(GEN x, GEN y, ulong p) replaces x by x-y.

ulong Flv_dotproduct(GEN x, GEN y, ulong p) returns the scalar product of x and y

ulong Flv_dotproduct_pre(GEN x, GEN y, ulong p, ulong pi) returns the scalar product of x and y assuming pi is the pseudo inverse of p.

ulong Flv_sum(GEN x, ulong p) returns the sum of the components of x.

ulong Flv_prod(GEN x, ulong p) returns the product of the components of x.

ulong Flv_prod_pre(GEN x, ulong p, ulong pi) as Flv_prod assuming pi is the pseudo inverse of p.

GEN Flv_inv(GEN x, ulong p) returns the vector of inverses of the elements of x (as a Flv). Use Montgomery trick.

void Flv_inv_inplace(GEN x, ulong p) in place variant of Flv_inv.

GEN Flv_inv_pre(GEN x, ulong p, ulong pi) as Flv_inv assuming pi is the pseudo inverse of p.

void Flv_inv_pre_inplace(GEN x, ulong p, ulong pi) in place variant of Flv_inv.

GEN zero_Flm(long m, long n) creates a Flm with m x n components set to 0. Note that the result allocates a single column, so modifying an entry in one column modifies it in all columns.

GEN zero_Flm_copy(long m, long n) creates a Flm with m x n components set to 0.

GEN zero_Flv(long n) creates a Flv with n components set to 0.

GEN Flm_row(GEN A, long x0) return A[i,], the i-th row of the Flm A.

GEN Flm_add(GEN x, GEN y, ulong p) adds x and y (assumed to have compatible dimensions).

GEN Flm_sub(GEN x, GEN y, ulong p) subtracts x and y (assumed to have compatible dimensions).

GEN Flm_mul(GEN x, GEN y, ulong p) multiplies x and y (assumed to have compatible dimensions).

GEN Flm_powu(GEN x, ulong n, ulong p) computes x^n where x is a square Flm.

GEN Flm_charpoly(GEN x, ulong p) return the characteristic polynomial of the square Flm x, as a Flx.

GEN Flm_deplin(GEN x, ulong p)

ulong Flm_det(GEN x, ulong p)

ulong Flm_det_sp(GEN x, ulong p), as Flm_det, in place (destroys x).

GEN Flm_gauss(GEN a, GEN b, ulong p) as gauss, where b is a Flm.

GEN Flm_Flc_gauss(GEN a, GEN b, ulong p) as gauss, where b is a Flc.

GEN Flm_indexrank(GEN x, ulong p)

GEN Flm_inv(GEN x, ulong p)

GEN Flm_Flc_invimage(GEN A, GEN y, ulong p) given an Flm A and an Flc y, returns an x such that Ax = y, or NULL if no such vector exist.

GEN Flm_invimage(GEN A, GEN y, ulong p) given two Flm A and y, returns x such that Ax = y, or NULL if no such matrix exist.

GEN Flm_ker(GEN x, ulong p)

GEN Flm_ker_sp(GEN x, ulong p, long deplin), as Flm_ker (if deplin = 0) or Flm_deplin (if deplin = 1) , in place (destroys x).

long Flm_rank(GEN x, ulong p)

long Flm_suppl(GEN x, ulong p)

GEN Flm_image(GEN x, ulong p)

GEN Flm_intersect(GEN x, GEN y, ulong p)

GEN Flm_transpose(GEN x)

GEN Flm_hess(GEN x, ulong p) upper Hessenberg form of x over F_p.

## F2c / F2v, F2m

An F2v v is a t_VECSMALL representing a vector over F_2. Specifically z[0] is the usual codeword, z[1] is the number of components of v and the coefficients are given by the bits of remaining words by increasing indices.

ulong F2v_coeff(GEN x, long i) returns the coefficient i >= 1 of x.

void F2v_clear(GEN x, long i) sets the coefficient i >= 1 of x to 0.

void F2v_flip(GEN x, long i) adds 1 to the coefficient i >= 1 of x.

void F2v_set(GEN x, long i) sets the coefficient i >= 1 of x to 1.

void F2v_copy(GEN x) returns a copy of x.

GEN F2v_slice(GEN x, long a, long b) returns the F2v with entries x[a],..., x[b]. Assumes a <= b.

ulong F2m_coeff(GEN x, long i, long j) returns the coefficient (i,j) of x.

void F2m_clear(GEN x, long i, long j) sets the coefficient (i,j) of x to 0.

void F2m_flip(GEN x, long i, long j) adds 1 to the coefficient (i,j) of x.

void F2m_set(GEN x, long i, long j) sets the coefficient (i,j) of x to 1.

void F2m_copy(GEN x) returns a copy of x.

GEN F2m_rowslice(GEN x, long a, long b) returns the F2m built from the a-th to b-th rows of the F2m x. Assumes a <= b.

GEN F2m_F2c_mul(GEN x, GEN y) multiplies x and y (assumed to have compatible dimensions).

GEN F2m_image(GEN x) gives a subset of the columns of x that generate the image of x.

GEN F2m_invimage(GEN A, GEN B)

GEN F2m_F2c_invimage(GEN A, GEN y)

GEN F2m_gauss(GEN a, GEN b) as gauss, where b is a F2m.

GEN F2m_F2c_gauss(GEN a, GEN b) as gauss, where b is a F2c.

GEN F2m_indexrank(GEN x) x being a matrix of rank r, returns a vector with two t_VECSMALL components y and z of length r giving a list of rows and columns respectively (starting from 1) such that the extracted matrix obtained from these two vectors using vecextract(x,y,z) is invertible.

GEN F2m_mul(GEN x, GEN y) multiplies x and y (assumed to have compatible dimensions).

GEN F2m_powu(GEN x, ulong n) computes x^n where x is a square F2m.

long F2m_rank(GEN x) as rank.

long F2m_suppl(GEN x) as suppl.

GEN matid_F2m(long n) returns an F2m which is an n x n identity matrix.

GEN zero_F2v(long n) creates a F2v with n components set to 0.

GEN const_F2v(long n) creates a F2v with n components set to 1.

GEN F2v_ei(long n, long i) creates a F2v with n components set to 0, but for the i-th one, which is set to 1 (i-th vector in the canonical basis).

GEN zero_F2m(long m, long n) creates a Flm with m x n components set to 0. Note that the result allocates a single column, so modifying an entry in one column modifies it in all columns.

GEN zero_F2m_copy(long m, long n) creates a F2m with m x n components set to 0.

GEN F2v_to_Flv(GEN x)

GEN F2c_to_ZC(GEN x)

GEN ZV_to_F2v(GEN x)

GEN RgV_to_F2v(GEN x)

GEN F2m_to_Flm(GEN x)

GEN F2m_to_ZM(GEN x)

GEN Flv_to_F2v(GEN x)

GEN Flm_to_F2m(GEN x)

GEN ZM_to_F2m(GEN x)

GEN RgM_to_F2m(GEN x)

void F2v_add_inplace(GEN x, GEN y) replaces x by x+y. It is allowed for y to be shorter than x.

ulong F2m_det(GEN x)

ulong F2m_det_sp(GEN x), as F2m_det, in place (destroys x).

GEN F2m_deplin(GEN x)

ulong F2v_dotproduct(GEN x, GEN y) returns the scalar product of x and y

GEN F2m_inv(GEN x)

GEN F2m_ker(GEN x)

GEN F2m_ker_sp(GEN x, long deplin), as F2m_ker (if deplin = 0) or F2m_deplin (if deplin = 1), in place (destroys x).

## FlxqV, FlxqM

See FqV, FqM operations.

GEN FlxqV_dotproduct(GEN x, GEN y, GEN T, ulong p) as FpV_dotproduct.

GEN FlxM_Flx_add_shallow(GEN x, GEN y, ulong p) as RgM_Rg_add_shallow.

GEN FlxqM_gauss(GEN a, GEN b, GEN T, ulong p)

GEN FlxqM_FlxqC_gauss(GEN a, GEN b, GEN T, ulong p)

GEN FlxqM_FlxqC_mul(GEN a, GEN b, GEN T, ulong p)

GEN FlxqM_ker(GEN x, GEN T, ulong p)

GEN FlxqM_image(GEN x, GEN T, ulong p)

GEN FlxqM_det(GEN a, GEN T, ulong p)

GEN FlxqM_inv(GEN x, GEN T, ulong p)

GEN FlxqM_mul(GEN a, GEN b, GEN T, ulong p)

long FlxqM_rank(GEN x, GEN T, ulong p)

GEN matid_FlxqM(long n, GEN T, ulong p)

## FpX

Let p an understood t_INT, to be given in the function arguments; in practice p is not assumed to be prime, but be wary. Recall than an Fp object is a t_INT, preferably belonging to [0, p-1]; an FpX is a t_POL in a fixed variable whose coefficients are Fp objects. Unless mentioned otherwise, all outputs in this section are FpXs. All operations are understood to take place in (Z/pZ)[X].

### Conversions In what follows p is always a t_INT,

not necessarily prime.

int RgX_is_FpX(GEN z, GEN *p), z a t_POL, checks if it can be mapped to a FpX, by checking Rg_is_Fp coefficientwise.

GEN RgX_to_FpX(GEN z, GEN p), z a t_POL, returns the FpX obtained by applying Rg_to_Fp coefficientwise.

GEN FpX_red(GEN z, GEN p), z a ZX, returns lift(z * Mod(1,p)), normalized.

GEN FpXV_red(GEN z, GEN p), z a t_VEC of ZX. Applies FpX_red componentwise and returns the result (and we obtain a vector of FpXs).

GEN FpXT_red(GEN z, GEN p), z a tree of ZX. Applies FpX_red to each leaf and returns the result (and we obtain a tree of FpXs).

### Basic operations In what follows p is always a t_INT,

not necessarily prime.

@3Now, except for p, the operands and outputs are all FpX objects. Results are undefined on other inputs.

GEN FpX_add(GEN x,GEN y, GEN p) adds x and y.

GEN FpX_neg(GEN x,GEN p) returns -x, the components are between 0 and p if this is the case for the components of x.

GEN FpX_renormalize(GEN x, long l), as normalizepol, where l = lg(x), in place.

GEN FpX_sub(GEN x,GEN y,GEN p) returns x-y.

GEN FpX_halve(GEN x, GEN m) returns z such that 2 z = x modulo m assuming such z exists.

GEN FpX_mul(GEN x,GEN y,GEN p) returns x y.

GEN FpX_mulspec(GEN a, GEN b, GEN p, long na, long nb) see ZX_mulspec

GEN FpX_sqr(GEN x,GEN p) returns x^2.

GEN FpX_powu(GEN x, ulong n, GEN p) returns x^n.

GEN FpX_divrem(GEN x, GEN y, GEN p, GEN *pr) returns the quotient of x by y, and sets pr to the remainder.

GEN FpX_div(GEN x, GEN y, GEN p) returns the quotient of x by y.

GEN FpX_div_by_X_x(GEN A, GEN a, GEN p, GEN *r) returns the quotient of the FpX A by (X - a), and sets r to the remainder A(a).

GEN FpX_rem(GEN x, GEN y, GEN p) returns the remainder x mod y.

long FpX_valrem(GEN x, GEN t, GEN p, GEN *r) The arguments x and e being non-zero FpX returns the highest exponent e such that t^{e} divides x. The quotient x/t^{e} is returned in *r. In particular, if t is irreducible, this returns the valuation at t of x, and *r is the prime-to-t part of x.

GEN FpX_deriv(GEN x, GEN p) returns the derivative of x. This function is not memory-clean, but nevertheless suitable for gerepileupto.

GEN FpX_digits(GEN x, GEN B, GEN p) returns a vector of FpX [c_0,...,c_n] of degree less than the degree of B and such that x = sum_{i = 0}^{n}{c_i B^i}.

GEN FpX_fromdigits(GEN v, GEN B, GEN p) where v = [c_0,...,c_n] is a vector of FpX, returns sum_{i = 0}^{n}{c_i B^i}.

GEN FpX_translate(GEN P, GEN c, GEN p) let c be an Fp and let P be an FpX; returns the translated FpX of P(X+c).

GEN FpX_gcd(GEN x, GEN y, GEN p) returns a (not necessarily monic) greatest common divisor of x and y.

GEN FpX_halfgcd(GEN x, GEN y, GEN p) returns a two-by-two FpXM M with determinant +- 1 such that the image (a,b) of (x,y) by M has the property that deg  a >= ( deg  x )/(2) >  deg  b.

GEN FpX_extgcd(GEN x, GEN y, GEN p, GEN *u, GEN *v) returns d = GCD(x,y) (not necessarily monic), and sets *u, *v to the Bezout coefficients such that *ux + *vy = d. If *u is set to NULL, it is not computed which is a bit faster. This is useful when computing the inverse of y modulo x.

GEN FpX_center(GEN z, GEN p, GEN pov2) returns the polynomial whose coefficient belong to the symmetric residue system. Assumes the coefficients already belong to [0,p-1]) and pov2 is shifti(p,-1).

GEN FpX_Frobenius(GEN T, GEN p) returns X^{p} (mod T(X)).

GEN FpX_matFrobenius(GEN T, GEN p) returns the matrix of the Frobenius automorphism x:--->x^p over the power basis of F_p[X]/(T).

### Mixed operations

The following functions implement arithmetic operations between FpX and Fp operands, the result being of type FpX. The integer p need not be prime.

GEN Z_to_FpX(GEN x, GEN p, long v) converts a t_INT to a scalar polynomial in variable v, reduced modulo p.

GEN FpX_Fp_add(GEN y, GEN x, GEN p) add the Fp x to the FpX y.

GEN FpX_Fp_add_shallow(GEN y, GEN x, GEN p) add the Fp x to the FpX y, using a shallow copy (result not suitable for gerepileupto)

GEN FpX_Fp_sub(GEN y, GEN x, GEN p) subtract the Fp x from the FpX y.

GEN FpX_Fp_sub_shallow(GEN y, GEN x, GEN p) subtract the Fp x from the FpX y, using a shallow copy (result not suitable for gerepileupto)

GEN Fp_FpX_sub(GEN x,GEN y,GEN p) returns x - y, where x is a t_INT and y an FpX.

GEN FpX_Fp_mul(GEN x, GEN y, GEN p) multiplies the FpX x by the Fp y.

GEN FpX_Fp_mulspec(GEN x, GEN y, GEN p, long lx) see ZX_mulspec

GEN FpX_mulu(GEN x, ulong y, GEN p) multiplies the FpX x by y.

GEN FpX_Fp_mul_to_monic(GEN y,GEN x,GEN p) returns y x assuming the result is monic of the same degree as y (in particular x != 0).

### Miscellaneous operations

GEN FpX_normalize(GEN z, GEN p) divides the FpX z by its leading coefficient. If the latter is 1, z itself is returned, not a copy. If not, the inverse remains uncollected on the stack.

GEN FpX_invBarrett(GEN T, GEN p), returns the Barrett inverse M of T defined by M(x) x^n T(1/x) = 1 (mod x^{n-1}) where n is the degree of T.

GEN FpX_rescale(GEN P, GEN h, GEN p) returns h^{ deg (P)} P(x/h). P is an FpX and h is a non-zero Fp (the routine would work with any non-zero t_INT but is not efficient in this case).

GEN FpX_eval(GEN x, GEN y, GEN p) evaluates the FpX x at the Fp y. The result is an Fp.

GEN FpX_FpV_multieval(GEN P, GEN v, GEN p) returns the vector [P(v[1]),...,P(v[n])] as a FpV.

GEN FpX_dotproduct(GEN x, GEN y, GEN p) return the scalar product sum_{i >= 0} x_i y_i of the coefficients of x and y.

GEN FpXV_FpC_mul(GEN V, GEN W, GEN p) multiplies a non-empty line vector ofFpX by a column vector of Fp of compatible dimensions. The result is an FpX.

GEN FpXV_prod(GEN V, GEN p), V being a vector of FpX, returns their product.

GEN FpV_roots_to_pol(GEN V, GEN p, long v), V being a vector of INTs, returns the monic FpX prod_i (pol_x[v] - V[i]).

GEN FpX_chinese_coprime(GEN x,GEN y, GEN Tx,GEN Ty, GEN Tz, GEN p): returns an FpX, congruent to x mod Tx and to y mod Ty. Assumes Tx and Ty are coprime, and Tz = Tx * Ty or NULL (in which case it is computed within).

GEN FpV_polint(GEN x, GEN y, GEN p, long v) returns the FpX interpolation polynomial with value y[i] at x[i]. Assumes lengths are the same, components are t_INTs, and the x[i] are distinct modulo p.

GEN FpV_FpM_polint(GEN x, GEN V, GEN p, long v) equivalent (but faster) to applying FpV_polint(x,...) to all the elements of the vector V (thus, returns a FpXV).

GEN FpV_invVandermonde(GEN L, GEN d, GEN p) L being a FpV of length n, return the inverse M of the Vandermonde matrix attached to the elements of L, eventually multiplied by d if it is not NULL. If A is a FpV and B = M A, then the polynomial P = sum_{i = 1}^n B[i] X^{i-1} verifies P(L[i]) = d A[i] for 1 <= i <= n.

int FpX_is_squarefree(GEN f, GEN p) returns 1 if the FpX f is squarefree, 0 otherwise.

int FpX_is_irred(GEN f, GEN p) returns 1 if the FpX f is irreducible, 0 otherwise. Assumes that p is prime. If f has few factors, FpX_nbfact(f,p) == 1 is much faster.

int FpX_is_totally_split(GEN f, GEN p) returns 1 if the FpX f splits into a product of distinct linear factors, 0 otherwise. Assumes that p is prime.

GEN FpX_factor(GEN f, GEN p), factors the FpX f. Assumes that p is prime. The returned value v is a t_VEC with two components: v[1] is a vector of distinct irreducible (FpX) factors, and v[2] is a t_VECSMALL of corresponding exponents. The order of the factors is deterministic (the computation is not).

GEN FpX_factor_squarefree(GEN f, GEN p) returns the squarefree factorization of f modulo p. This is a vector [u_1,...,u_k] of pairwise coprime FpX such that u_k != 1 and f = prod u_i^i. Shallow function.

long FpX_nbfact(GEN f, GEN p), assuming the FpX f is squarefree, returns the number of its irreducible factors. Assumes that p is prime.

long FpX_nbfact_Frobenius(GEN f, GEN XP, GEN p), as FpX_nbfact(f, p) but faster, where XP is FpX_Frobenius(f, p).

long FpX_degfact(GEN f, GEN p), as FpX_factor, but the degrees of the irreducible factors are returned instead of the factors themselves (as a t_VECSMALL). Assumes that p is prime.

long FpX_nbroots(GEN f, GEN p) returns the number of distinct roots in Z/pZ of the FpX f. Assumes that p is prime.

GEN FpX_oneroot(GEN f, GEN p) returns one root in Z/pZ of the FpX f. Return NULL if no root exists. Assumes that p is prime.

GEN FpX_roots(GEN f, GEN p) returns the roots in Z/pZ of the FpX f (without multiplicity, as a vector of Fps). Assumes that p is prime.

GEN FpX_split_part(GEN f, GEN p) returns the largest totally split squarefree factor of f.

GEN random_FpX(long d, long v, GEN p) returns a random FpX in variable v, of degree less than d.

GEN FpX_resultant(GEN x, GEN y, GEN p) returns the resultant of x and y, both FpX. The result is a t_INT belonging to [0,p-1].

GEN FpX_disc(GEN x, GEN p) returns the discriminant of the FpX x. The result is a t_INT belonging to [0,p-1].

GEN FpX_FpXY_resultant(GEN a, GEN b, GEN p), a a t_POL of t_INTs (say in variable X), b a t_POL (say in variable X) whose coefficients are either t_POLs in Z[Y] or t_INTs. Returns Res_X(a, b) in F_p[Y] as an FpY. The function assumes that X has lower priority than Y.

## FpXQ, Fq

Let p a t_INT and T an FpX for p, both to be given in the function arguments; an FpXQ object is an FpX whose degree is strictly less than the degree of T. An Fq is either an FpXQ or an Fp. Both represent a class in (Z/pZ)[X] / (T), in which all operations below take place. In addition, Fq routines also allow T = NULL, in which case no reduction mod T is performed on the result.

For efficiency, the routines in this section may leave small unused objects behind on the stack (their output is still suitable for gerepileupto). Besides T and p, arguments are either FpXQ or Fq depending on the function name. (All Fq routines accept FpXQs by definition, not the other way round.)

### Preconditioned reduction

For faster reduction, the modulus T can be replaced by an extended modulus, which is an FpXT, in all FpXQ- and Fq-classes functions, and in FpX_rem and FpX_divrem.

GEN FpX_get_red(GEN T, GEN p) returns the extended modulus eT.

To write code that works both with plain and extended moduli, the following accessors are defined:

GEN get_FpX_mod(GEN eT) returns the underlying modulus T.

GEN get_FpX_var(GEN eT) returns the variable number of the modulus.

GEN get_FpX_degree(GEN eT) returns the degree of the modulus.

Furthermore, ZXT_to_FlxT allows to convert an extended modulus for a FpX to an extended modulus for the corresponding Flx.

### Conversions

GEN Rg_is_FpXQ(GEN z, GEN *T, GEN *p), checks if z is a GEN which can be mapped to F_p[X]/(T): anything for which Rg_is_Fp return 1, a t_POL for which RgX_to_FpX return 1, a t_POLMOD whose modulus is equal to *T if *T is not NULL (once mapped to a FpX), or a t_FFELT z such that z^0 is equal to *T if *T is not NULL.

If an integer modulus is found it is put in *p, else *p is left unchanged. If a polynomial modulus is found it is put in *T, if a t_FFELT z is found, z^0 is put in *T, else *T is left unchanged.

int RgX_is_FpXQX(GEN z, GEN *T, GEN *p), z a t_POL, checks if it can be mapped to a FpXQX, by checking Rg_is_FpXQ coefficientwise.

GEN Rg_to_FpXQ(GEN z, GEN T, GEN p), z a GEN which can be mapped to F_p[X]/(T): anything Rg_to_Fp can be applied to, a t_POL to which RgX_to_FpX can be applied to, a t_POLMOD whose modulus is divisible by T (once mapped to a FpX), a suitable t_RFRAC. Returns z as an FpXQ, normalized.

GEN RgX_to_FpXQX(GEN z, GEN T, GEN p), z a t_POL, returns the FpXQ obtained by applying Rg_to_FpXQ coefficientwise.

GEN RgX_to_FqX(GEN z, GEN T, GEN p): let z be a t_POL; returns the FqX obtained by applying Rg_to_FpXQ coefficientwise and simplifying scalars to t_INTs.

GEN Fq_to_FpXQ(GEN z, GEN T, GEN p /*unused*/) if z is a t_INT, convert it to a constant polynomial in the variable of T, otherwise return z (shallow function).

GEN Fq_red(GEN x, GEN T, GEN p), x a ZX or t_INT, reduce it to an Fq (T = NULL is allowed iff x is a t_INT).

GEN FqX_red(GEN x, GEN T, GEN p), x a t_POL whose coefficients are ZXs or t_INTs, reduce them to Fqs. (If T = NULL, as FpXX_red(x, p).)

GEN FqV_red(GEN x, GEN T, GEN p), x a vector of ZXs or t_INTs, reduce them to Fqs. (If T = NULL, only reduce components mod p to FpXs or Fps.)

GEN FpXQ_red(GEN x, GEN T,GEN p) x a t_POL whose coefficients are t_INTs, reduce them to FpXQs.

## FpXQ

GEN FpXQ_add(GEN x, GEN y, GEN T,GEN p)

GEN FpXQ_sub(GEN x, GEN y, GEN T,GEN p)

GEN FpXQ_mul(GEN x, GEN y, GEN T,GEN p)

GEN FpXQ_sqr(GEN x, GEN T, GEN p)

GEN FpXQ_div(GEN x, GEN y, GEN T,GEN p)

GEN FpXQ_inv(GEN x, GEN T, GEN p) computes the inverse of x

GEN FpXQ_invsafe(GEN x,GEN T,GEN p), as FpXQ_inv, returning NULL if x is not invertible.

GEN FpXQ_pow(GEN x, GEN n, GEN T, GEN p) computes x^n.

GEN FpXQ_powu(GEN x, ulong n, GEN T, GEN p) computes x^n for small n.

In the following three functions the integer parameter ord can be given either as a positive t_INT N, or as its factorization matrix faN, or as a pair [N,faN]. The parameter may be omitted by setting it to NULL (the value is then p^d-1, d =  deg  T).

GEN FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p) Let g be of order ord in the finite field F_p[X]/(T), return e such that a^e = g. If e does not exists, the result is undefined. Assumes that T is irreducible mod p.

GEN Fp_FpXQ_log(GEN a, GEN g, GEN ord, GEN T, GEN p) As FpXQ_log, a being a Fp.

GEN FpXQ_order(GEN a, GEN ord, GEN T, GEN p) returns the order of the FpXQ a. Assume that ord is a multiple of the order of a. Assume that T is irreducible mod p.

int FpXQ_issquare(GEN x, GEN T, GEN p) returns 1 if x is a square and 0 otherwise. Assumes that T is irreducible mod p.

GEN FpXQ_sqrt(GEN x, GEN T, GEN p) returns a square root of x. Return NULL if x is not a square.

GEN FpXQ_sqrtn(GEN x, GEN n, GEN T, GEN p, GEN *zn) Let Tbe irreducible mod p and q = p^{ deg  T}; returns NULL if a is not an n-th power residue mod p. Otherwise, returns an n-th root of a; if zn is non-NULL set it to a primitive m-th root of 1 in F_q, m =  gcd (q-1,n) allowing to compute all m solutions in F_q of the equation x^n = a.

## Fq

GEN Fq_add(GEN x, GEN y, GEN T/*unused*/, GEN p)

GEN Fq_sub(GEN x, GEN y, GEN T/*unused*/, GEN p)

GEN Fq_mul(GEN x, GEN y, GEN T, GEN p)

GEN Fq_Fp_mul(GEN x, GEN y, GEN T, GEN p) multiplies the Fq x by the t_INT y.

GEN Fq_mulu(GEN x, ulong y, GEN T, GEN p) multiplies the Fq x by the scalar y.

GEN Fq_halve(GEN x, GEN T, GEN p) returns z such that 2 z = x assuming such z exists.

GEN Fq_sqr(GEN x, GEN T, GEN p)

GEN Fq_neg(GEN x, GEN T, GEN p)

GEN Fq_neg_inv(GEN x, GEN T, GEN p) computes -x^{-1}

GEN Fq_inv(GEN x, GEN pol, GEN p) computes x^{-1}, raising an error if x is not invertible.

GEN Fq_invsafe(GEN x, GEN pol, GEN p) as Fq_inv, but returns NULL if x is not invertible.

GEN Fq_div(GEN x, GEN y, GEN T, GEN p)

GEN FqV_inv(GEN x, GEN T, GEN p) x being a vector of Fqs, return the vector of inverses of the x[i]. The routine uses Montgomery's trick, and involves a single inversion, plus 3(N-1) multiplications for N entries. The routine is not stack-clean: 2N FpXQ are left on stack, besides the N in the result.

GEN Fq_pow(GEN x, GEN n, GEN pol, GEN p) returns x^n.

GEN Fq_powu(GEN x, ulong n, GEN pol, GEN p) returns x^n for small n.

GEN Fq_log(GEN a, GEN g, GEN ord, GEN T, GEN p) as Fp_log or FpXQ_log.

int Fq_issquare(GEN x, GEN T, GEN p) returns 1 if x is a square and 0 otherwise. Assumes that T is irreducible mod p and that p is prime; T = NULL is forbidden unless x is an Fp.

long Fq_ispower(GEN x, GEN n, GEN T, GEN p) returns 1 if x is a n-th power and 0 otherwise. Assumes that T is irreducible mod p and that p is prime; T = NULL is forbidden unless x is an Fp.

GEN Fq_sqrt(GEN x, GEN T, GEN p) returns a square root of x. Return NULL if x is not a square.

GEN Fq_sqrtn(GEN a, GEN n, GEN T, GEN p, GEN *zn) as FpXQ_sqrtn.

GEN FpXQ_charpoly(GEN x, GEN T, GEN p) returns the characteristic polynomial of x

GEN FpXQ_minpoly(GEN x, GEN T, GEN p) returns the minimal polynomial of x

GEN FpXQ_norm(GEN x, GEN T, GEN p) returns the norm of x

GEN FpXQ_trace(GEN x, GEN T, GEN p) returns the trace of x

GEN FpXQ_conjvec(GEN x, GEN T, GEN p) returns the vector of conjugates [x,x^p,x^{p^2},...,x^{p^{n-1}}] where n is the degree of T.

GEN gener_FpXQ(GEN T, GEN p, GEN *po) returns a primitive root modulo (T,p). T is an FpX assumed to be irreducible modulo the prime p. If po is not NULL it is set to [o,fa], where o is the order of the multiplicative group of the finite field, and fa is its factorization.

GEN gener_FpXQ_local(GEN T, GEN p, GEN L), L being a vector of primes dividing p^{ deg  T} - 1, returns an element of G := F_p[x]/(T) which is a generator of the ell-Sylow of G for every ell in L. It is not necessary, and in fact slightly inefficient, to include ell = 2, since 2 is treated separately in any case, i.e. the generator obtained is never a square if p is odd.

GEN gener_Fq_local(GEN T, GEN p, GEN L) as pgener_Fp_local(p, L) if T is NULL, or gener_FpXQ_local (otherwise).

GEN FpXQ_powers(GEN x, long n, GEN T, GEN p) returns [x^0, ..., x^n] as a t_VEC of FpXQs.

GEN FpXQ_matrix_pow(GEN x, long m, long n, GEN T, GEN p), as FpXQ_powers(x, n-1, T, p), but returns the powers as a an m x n matrix. Usually, we have m = n =  deg  T.

GEN FpXQ_autpow(GEN a, ulong n, GEN T, GEN p) computes sigma^n(X) assuming a = sigma(X) where sigma is an automorphism of the algebra F_p[X]/T(X).

GEN FpXQ_autsum(GEN a, ulong n, GEN T, GEN p) a being a two-component vector, sigma being the automorphism defined by sigma(X) = a[1] (mod T(X)), returns the vector [sigma^n(X),bsigma(b)...sigma^{n-1}(b)] where b = a[2].

GEN FpXQ_auttrace(GEN a, ulong n, GEN T, GEN p) a being a two-component vector, sigma being the automorphism defined by sigma(X) = a[1] (mod T(X)), returns the vector [sigma^n(X),b+sigma(b)+...+sigma^{n-1}(b)] where b = a[2].

GEN FpXQ_autpowers(GEN S, long n, GEN T, GEN p) returns [x,S(x),S(S(x)),...,S^{(n)}(x)] as a t_VEC of FpXQs.

GEN FpXQM_autsum(GEN a, long n, GEN T, GEN p) sigma being the automorphism defined by sigma(X) = a[1] (mod T(X)), returns the vector [sigma^n(X),bsigma(b)...sigma^{n-1}(b)] where b = a[2] is a square matrix.

GEN FpX_FpXQ_eval(GEN f, GEN x, GEN T, GEN p) returns f(x).

GEN FpX_FpXQV_eval(GEN f, GEN V, GEN T, GEN p) returns f(x), assuming that V was computed by FpXQ_powers(x, n, T, p).

GEN FpXC_FpXQV_eval(GEN C, GEN V,GEN T,GEN p) applies FpX_FpXQV_eval to all elements of the vector C and returns a t_COL.

GEN FpXM_FpXQV_eval(GEN M, GEN V,GEN T,GEN p) applies FpX_FpXQV_eval to all elements of the matrix M.

## FpXX, FpXY

Contrary to what the name implies, an FpXX is a t_POL whose coefficients are either t_INTs or FpXs. This reduces memory overhead at the expense of consistency. The prefix FpXY is an alias for FpXX when variables matters.

GEN FpXX_red(GEN z, GEN p), z a t_POL whose coefficients are either ZXs or t_INTs. Returns the t_POL equal to z with all components reduced modulo p.

GEN FpXX_renormalize(GEN x, long l), as normalizepol, where l = lg(x), in place.

GEN FpXX_add(GEN x, GEN y, GEN p) adds x and y.

GEN FpXX_sub(GEN x, GEN y, GEN p) returns x-y.

GEN FpXX_neg(GEN x, GEN p) returns -x.

GEN FpXX_Fp_mul(GEN x, GEN y, GEN p) multiplies the FpXX x by the Fp y.

GEN FpXX_FpX_mul(GEN x, GEN y, GEN p) multiplies the coefficients of the FpXX x by the FpX y.

GEN FpXX_mulu(GEN x, GEN y, GEN p) multiplies the FpXX x by the scalar y.

GEN FpXX_deriv(GEN P, GEN p) differentiates P with respect of the main variable.

GEN FpXY_eval(GEN Q, GEN y, GEN x, GEN p) Q being an FpXY, i.e. a t_POL with Fp or FpX coefficients representing an element of F_p[X][Y]. Returns the Fp Q(x,y).

GEN FpXY_evalx(GEN Q, GEN x, GEN p) Q being an FpXY, returns the FpX Q(x,Y), where Y is the main variable of Q.

GEN FpXY_evaly(GEN Q, GEN y, GEN p, long vx) Q an FpXY, returns the FpX Q(X,y), where X is the second variable of Q, and vx is the variable number of X.

GEN FpXY_Fq_evaly(GEN Q, GEN y, GEN T, GEN p, long vx) Q an FpXY and y being an Fq, returns the FqX Q(X,y), where X is the second variable of Q, and vx is the variable number of X.

GEN FpXY_FpXQ_evalx(GEN Q, GEN x, ulong p) Q an FpXY and x being an FpXQ, returns the FpXQX Q(x,Y), where Y is the first variable of Q.

GEN FpXY_FpXQV_evalx(GEN Q, GEN V, ulong p) Q an FpXY and x being an FpXQ, returns the FpXQX Q(x,Y), where Y is the first variable of Q, assuming that V was computed by FpXQ_powers(x, n, T, p).

GEN FpXYQQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p), x being a FpXY, T being a FpX and S being a FpY, return x^n (mod S,T,p).

## FpXQX, FqX

Contrary to what the name implies, an FpXQX is a t_POL whose coefficients are Fqs. So the only difference between FqX and FpXQX routines is that T = NULL is not allowed in the latter. (It was thought more useful to allow t_INT components than to enforce strict consistency, which would not imply any efficiency gain.)

### Basic operations

GEN FqX_add(GEN x,GEN y,GEN T,GEN p)

GEN FqX_Fq_add(GEN x, GEN y, GEN T, GEN p) adds the Fq y to the FqX x.

GEN FqX_neg(GEN x,GEN T,GEN p)

GEN FqX_sub(GEN x,GEN y,GEN T,GEN p)

GEN FqX_mul(GEN x, GEN y, GEN T, GEN p)

GEN FqX_Fq_mul(GEN x, GEN y, GEN T, GEN p) multiplies the FqX x by the Fq y.

GEN FqX_mulu(GEN x, ulong y, GEN T, GEN p) multiplies the FqX x by the scalar y.

GEN FqX_Fp_mul(GEN x, GEN y, GEN T, GEN p) multiplies the FqX x by the t_INT y.

GEN FqX_Fq_mul_to_monic(GEN x, GEN y, GEN T, GEN p) returns x y assuming the result is monic of the same degree as x (in particular y != 0).

GEN FpXQX_normalize(GEN z, GEN T, GEN p)

GEN FqX_normalize(GEN z, GEN T, GEN p) divides the FqX z by its leading term. The leading coefficient becomes 1 as a t_INT.

GEN FqX_sqr(GEN x, GEN T, GEN p)

GEN FqX_powu(GEN x, ulong n, GEN T, GEN p)

GEN FqX_divrem(GEN x, GEN y, GEN T, GEN p, GEN *z)

GEN FqX_div(GEN x, GEN y, GEN T, GEN p)

GEN FqX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *r)

GEN FqX_rem(GEN x, GEN y, GEN T, GEN p)

GEN FqX_deriv(GEN x, GEN T, GEN p) returns the derivative of x. (This function is suitable for gerepilupto but not memory-clean.)

GEN FqX_translate(GEN P, GEN c, GEN T, GEN p) let c be an Fq defined modulo (p, T), and let P be an FqX; returns the translated FqX of P(X+c).

GEN FqX_gcd(GEN P, GEN Q, GEN T, GEN p) returns a (not necessarily monic) greatest common divisor of x and y.

GEN FqX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv) returns d = GCD(x,y) (not necessarily monic), and sets *u, *v to the Bezout coefficients such that *ux + *vy = d.

GEN FqX_halfgcd(GEN x, GEN y, GEN T, GEN p) returns a two-by-two FqXM M with determinant +- 1 such that the image (a,b) of (x,y) by M has the property that deg  a >= ( deg  x )/(2) >  deg  b.

GEN FqX_eval(GEN x, GEN y, GEN T, GEN p) evaluates the FqX x at the Fq y. The result is an Fq.

GEN FqXY_eval(GEN Q, GEN y, GEN x, GEN T, GEN p) Q an FqXY, i.e. a t_POL with Fq or FqX coefficients representing an element of F_q[X][Y]. Returns the Fq Q(x,y).

GEN FqXY_evalx(GEN Q, GEN x, GEN T, GEN p) Q being an FqXY, returns the FqX Q(x,Y), where Y is the main variable of Q.

GEN random_FpXQX(long d, long v, GEN T, GEN p) returns a random FpXQX in variable v, of degree less than d.

GEN FpXQX_renormalize(GEN x, long lx)

GEN FpXQX_red(GEN z, GEN T, GEN p) z a t_POL whose coefficients are ZXs or t_INTs, reduce them to FpXQs.

GEN FpXQX_mul(GEN x, GEN y, GEN T, GEN p)

GEN Kronecker_to_FpXQX(GEN z, GEN T, GEN p). Let n =  deg  T and let P(X,Y)\in Z[X,Y] lift a polynomial in K[Y], where K := F_p[X]/(T) and deg _X P < 2n-1 --- such as would result from multiplying minimal degree lifts of two polynomials in K[Y]. Let z = P(t,t^{2*n-1}) be a Kronecker form of P, this function returns Q\in Z[X,t] such that Q is congruent to P(X,t) mod (p, T(X)), deg _X Q < n, and all coefficients are in [0,p[. Not stack-clean. Note that t need not be the same variable as Y!

GEN FpXQX_FpXQ_mul(GEN x, GEN y, GEN T, GEN p)

GEN FpXQX_sqr(GEN x, GEN T, GEN p)

GEN FpXQX_divrem(GEN x, GEN y, GEN T, GEN p, GEN *pr)

GEN FpXQX_div(GEN x, GEN y, GEN T, GEN p)

GEN FpXQX_div_by_X_x(GEN a, GEN x, GEN T, GEN p, GEN *r)

GEN FpXQX_rem(GEN x, GEN y, GEN T, GEN p)

GEN FpXQX_powu(GEN x, ulong n, GEN T, GEN p) returns x^n.

GEN FpXQX_digits(GEN x, GEN B, GEN T, GEN p)

GEN FpXQX_fromdigits(GEN v, GEN B, GEN T, GEN p)

GEN FpXQX_invBarrett(GEN y, GEN T, GEN p) returns the Barrett inverse of the FpXQX y, namely a lift of 1/polrecip(y)+O(x^{ deg (y)-1}).

GEN FpXQXV_prod(GEN V, GEN T, GEN p), V being a vector of FpXQX, returns their product.

GEN FpXQX_gcd(GEN x, GEN y, GEN T, GEN p)

GEN FpXQX_extgcd(GEN x, GEN y, GEN T, GEN p, GEN *ptu, GEN *ptv)

GEN FpXQX_halfgcd(GEN x, GEN y, GEN T, GEN p)

GEN FpXQX_FpXQXQ_eval(GEN f,GEN x,GEN S, GEN T,GEN p) returns f(x).

## FpXQXQ, FqXQ

A FpXQXQ is a t_FpXQX which represents an element of the ring (Fp[X]/T(X))[Y]/S(X,Y), where T is a FpX and S a FpXQX modulo T. A FqXQ is identical except that T is allowed to be NULL in which case S must be a FpX.

### Preconditioned reduction

For faster reduction, the modulus S can be replaced by an extended modulus, which is an FpXQXT, in all FpXQXQ- and FqXQ-classes functions, and in FpXQX_rem and FpXQX_divrem.

GEN FpXQX_get_red(GEN S, GEN T, GEN p) returns the extended modulus eS.

GEN FqX_get_red(GEN S, GEN T, GEN p) identical, but allow T to be NULL, in which case it returns FpX_get_red(S,p).

To write code that works both with plain and extended moduli, the following accessors are defined:

GEN get_FpXQX_mod(GEN eS) returns the underlying modulus S.

GEN get_FpXQX_var(GEN eS) returns the variable number of the modulus.

GEN get_FpXQX_degree(GEN eS) returns the degree of the modulus.

Furthermore, ZXXT_to_FlxXT allows to convert an extended modulus for a FpXQX to an extended modulus for the corresponding FlxqX.

### basic operations

GEN FpXQX_FpXQXQV_eval(GEN f,GEN V,GEN S,GEN T,GEN p) returns f(x), assuming that V was computed by FpXQXQ_powers(x, n, S, T, p).

GEN FpXQXQ_div(GEN x, GEN y, GEN S, GEN T, GEN p), x, y and S being FpXQXs, returns x*y^{-1} modulo S.

GEN FpXQXQ_inv(GEN x, GEN S, GEN T, GEN p), x and S being FpXQXs, returns x^{-1} modulo S.

GEN FpXQXQ_invsafe(GEN x, GEN S, GEN T,GEN p), as FpXQXQ_inv, returning NULL if x is not invertible.

GEN FpXQXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p), x, y and S being FpXQXs, returns x y modulo S.

GEN FpXQXQ_sqr(GEN x, GEN S, GEN T, GEN p), x and S being FpXQXs, returns x^2 modulo S.

GEN FpXQXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p), x and S being FpXQXs, returns x^n modulo S.

GEN FpXQXQ_powers(GEN x, long n, GEN S, GEN T, GEN p), x and S being FpXQXs, returns [x^0,..., x^n] as a t_VEC of FpXQXQs.

GEN FpXQXQ_matrix_pow(GEN x, long m, long n, GEN S, GEN T, GEN p) returns the same powers of x as FpXQXQ_powers(x, n-1,S, T, p), but as an m x n matrix.

GEN FpXQXQV_autpow(GEN a, long n, GEN S, GEN T, GEN p) sigma being the automorphism defined by sigma(X) = a[1] (mod T(X)), sigma(Y) = a[2] (mod S(X,Y),T(X)), returns [sigma^n(X),sigma^n(Y)].

GEN FpXQXQV_autsum(GEN a, long n, GEN S, GEN T, GEN p) sigma being the automorphism defined by sigma(X) = a[1] (mod T(X)), sigma(Y) = a[2] (mod S(X,Y),T(X)), returns the vector [sigma^n(X),sigma^n(Y),bsigma(b)...sigma^{n-1}(b)] where b = a[3].

GEN FpXQXQV_auttrace(GEN a, long n, GEN S, GEN T, GEN p) sigma being the automorphism defined by sigma(X) = a[1] (mod T(X)), sigma(Y) = a[2] (mod S(X,Y),T(X)), returns the vector [sigma^n(X),sigma^n(Y),b+sigma(b)+...+sigma^{n-1}(b)] where b = a[3].

GEN FqXQ_add(GEN x, GEN y, GEN S, GEN T, GEN p), x, y and S being FqXs, returns x + y modulo S.

GEN FqXQ_sub(GEN x, GEN y, GEN S, GEN T, GEN p), x, y and S being FqXs, returns x - y modulo S.

GEN FqXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p), x, y and S being FqXs, returns x y modulo S.

GEN FqXQ_div(GEN x, GEN y, GEN S, GEN T, GEN p), x and S being FqXs, returns x/y modulo S.

GEN FqXQ_inv(GEN x, GEN S, GEN T, GEN p), x and S being FqXs, returns x^{-1} modulo S.

GEN FqXQ_invsafe(GEN x, GEN S, GEN T, GEN p) , as FqXQ_inv, returning NULL if x is not invertible.

GEN FqXQ_sqr(GEN x, GEN S, GEN T, GEN p), x and S being FqXs, returns x^2 modulo S.

GEN FqXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p), x and S being FqXs, returns x^n modulo S.

GEN FqXQ_powers(GEN x, long n, GEN S, GEN T, GEN p), x and S being FqXs, returns [x^0,..., x^n] as a t_VEC of FqXQs.

GEN FqXQ_matrix_pow(GEN x, long m, long n, GEN S, GEN T, GEN p) returns the same powers of x as FqXQ_powers(x, n-1,S, T, p), but as an m x n matrix.

GEN FqV_roots_to_pol(GEN V, GEN T, GEN p, long v), V being a vector of Fqs, returns the monic FqX prod_i (pol_x[v] - V[i]).

### Miscellaneous operations

GEN init_Fq(GEN p, long n, long v) returns an irreducible polynomial of degree n > 0 over F_p, in variable v.

int FqX_is_squarefree(GEN P, GEN T, GEN p)

GEN FpXQX_roots(GEN x, GEN T, GEN p) return the roots of x in F_p[X]/(T). Assumes p is prime and T irreducible in F_p[X].

GEN FqX_roots(GEN x, GEN T, GEN p) same but allow T = NULL.

GEN FpXQX_factor(GEN x, GEN T, GEN p) same output convention as FpX_factor. Assumes p is prime and T irreducible in F_p[X].

GEN FqX_factor(GEN x, GEN T, GEN p) same but allow T = NULL.

GEN FpXQX_split_part(GEN f, GEN T, GEN p) returns the largest totally split squarefree factor of f.

long FqX_ispower(GEN f, ulong k, GEN T, GEN p, GEN *pt) return returns 1 if FqX f is a K-th power Return 0 otherwise. If py is not NULL, set it to g such that g^K = f.

GEN FpX_factorff(GEN P, GEN T, GEN p). Assumes p prime and T irreducible in F_p[X]. Factor the FpX P over the finite field F_p[Y]/(T(Y)). See FpX_factorff_irred if P is known to be irreducible of F_p.

GEN FpX_rootsff(GEN P, GEN T, GEN p). Assumes p prime and T irreducible in F_p[X]. Returns the roots of the FpX P belonging to the finite field F_p[Y]/(T(Y)).

GEN FpX_factorff_irred(GEN P, GEN T, GEN p). Assumes p prime and T irreducible in F_p[X]. Factors the irreducible FpX P over the finite field F_p[Y]/(T(Y)) and returns the vector of irreducible FqXs factors (the exponents, being all equal to 1, are not included).

GEN FpX_ffisom(GEN P, GEN Q, GEN p). Assumes p prime, P, Q are ZXs, both irreducible mod p, and deg (P) |  deg  Q. Outputs a monomorphism between F_p[X]/(P) and F_p[X]/(Q), as a polynomial R such that Q | P(R) in F_p[X]. If P and Q have the same degree, it is of course an isomorphism.

void FpX_ffintersect(GEN P, GEN Q, long n, GEN p, GEN *SP,GEN *SQ, GEN MA,GEN MB)\hfil

Assumes p is prime, P, Q are ZXs, both irreducible mod p, and n divides both the degree of P and Q. Compute SP and SQ such that the subfield of F_p[X]/(P) generated by SP and the subfield of F_p[X]/(Q) generated by SQ are isomorphic of degree n. The polynomials P and Q do not need to be of the same variable. If MA (resp. MB) is not NULL, it must be the matrix of the Frobenius map in F_p[X]/(P) (resp. F_p[X]/(Q)).

GEN FpXQ_ffisom_inv(GEN S, GEN T, GEN p). Assumes p is prime, T a ZX, which is irreducible modulo p, S a ZX representing an automorphism of F_q := F_p[X]/(T). (S(X) is the image of X by the automorphism.) Returns the inverse automorphism of S, in the same format, i.e. an FpX H such that H(S) = X modulo (T, p).

long FpXQX_nbfact(GEN S, GEN T, GEN p) returns the number of irreducible factors of the polynomial S over the finite field F_q defined by T and p.

long FqX_nbfact(GEN S, GEN T, GEN p) as above but accept T = NULL.

long FpXQX_nbroots(GEN S, GEN T, GEN p) returns the number of roots of the polynomial S over the finite field F_q defined by T and p.

long FqX_nbroots(GEN S, GEN T, GEN p) as above but accept T = NULL.

GEN FpXQX_Frobenius(GEN S, GEN T, GEN p) returns X^{q} (mod S(X)) over the finite field F_q defined by T and p, thus q = p^n where n is the degree of T.

GEN FpXQXQ_halfFrobenius(GEN A, GEN S, GEN T, GEN p) returns A(X)^{(q-1)/2} (mod S(X)) over the finite field F_q defined by T and p, thus q = p^n where n is the degree of T.

## Flx

Let p an understood ulong, assumed to be prime, to be given the function arguments; an Fl is an ulong belonging to [0,p-1], an Flx z is a t_VECSMALL representing a polynomial with small integer coefficients. Specifically z[0] is the usual codeword, z[1] = evalvarn(v) for some variable v, then the coefficients by increasing degree. An FlxX is a t_POL whose coefficients are Flxs.

@3In the following, an argument called sv is of the form evalvarn(v) for some variable number v.

### Preconditioned reduction

For faster reduction, the modulus T can be replaced by an extended modulus, which is an FlxT, in all Flxq-classes functions, and in Flx_divrem.

GEN Flx_get_red(GEN T, ulong p) returns the extended modulus eT.

To write code that works both with plain and extended moduli, the following accessors are defined:

GEN get_Flx_mod(GEN eT) returns the underlying modulus T.

GEN get_Flx_var(GEN eT) returns the variable number of the modulus.

GEN get_Flx_degree(GEN eT) returns the degree of the modulus.

Furthermore, ZXT_to_FlxT allows to convert an extended modulus for a FpX to an extended modulus for the corresponding Flx.

### Basic operations

ulong Flx_lead(GEN x) returns the leading coefficient of x as a ulong (return 0 for the zero polynomial).

GEN Flx_red(GEN z, ulong p) converts from zx with non-negative coefficients to Flx (by reducing them mod p).

int Flx_equal1(GEN x) returns 1 (true) if the Flx x is equal to 1, 0 (false) otherwise.

int Flx_equal(GEN x, GEN y) returns 1 (true) if the Flx x and y are equal, and 0 (false) otherwise.

GEN Flx_copy(GEN x) returns a copy of x.

GEN Flx_add(GEN x, GEN y, ulong p)

GEN Flx_Fl_add(GEN y, ulong x, ulong p)

GEN Flx_neg(GEN x, ulong p)

GEN Flx_neg_inplace(GEN x, ulong p), same as Flx_neg, in place (x is destroyed).

GEN Flx_sub(GEN x, GEN y, ulong p)

GEN Flx_halve(GEN x, ulong p) returns z such that 2 z = x modulo p assuming such z exists.

GEN Flx_mul(GEN x, GEN y, ulong p)

GEN Flx_Fl_mul(GEN y, ulong x, ulong p)

GEN Flx_double(GEN y, ulong p) returns 2 y.

GEN Flx_triple(GEN y, ulong p) returns 3 y.

GEN Flx_mulu(GEN y, ulong x, ulong p) as Flx_Fl_mul but do not assume that x < p.

GEN Flx_Fl_mul_to_monic(GEN y, ulong x, ulong p) returns y x assuming the result is monic of the same degree as y (in particular x != 0).

GEN Flx_sqr(GEN x, ulong p)

GEN Flx_powu(GEN x, ulong n, ulong p) returns x^n.

GEN Flx_divrem(GEN x, GEN y, ulong p, GEN *pr)

GEN Flx_div(GEN x, GEN y, ulong p)

GEN Flx_rem(GEN x, GEN y, ulong p)

GEN Flx_deriv(GEN z, ulong p)

GEN Flx_Frobenius(GEN T, ulong p)

GEN Flx_matFrobenius(GEN T, ulong p)

GEN Flx_gcd(GEN a, GEN b, ulong p) returns a (not necessarily monic) greatest common divisor of x and y.

GEN Flx_halfgcd(GEN x, GEN y, GEN p) returns a two-by-two FlxM M with determinant +- 1 such that the image (a,b) of (x,y) by M has the property that deg  a >= ( deg  x )/(2) >  deg  b.

GEN Flx_extgcd(GEN a, GEN b, ulong p, GEN *ptu, GEN *ptv)

GEN Flx_roots(GEN f, ulong p) returns the vector of roots of f (without multiplicity, as a t_VECSMALL). Assumes that p is prime.

ulong Flx_oneroot(GEN f, ulong p) returns one root 0 <= r < p of the Flx f in Z/pZ. Return p if no root exists. Assumes that p is prime.

ulong Flx_oneroot_split(GEN f, ulong p) as Flx_oneroot but assume f is totally split.

GEN Flx_roots_naive(GEN f, ulong p) returns the vector of roots of f as a t_VECSMALL (multiple roots are not repeated), found by an exhaustive search. Efficient for very small p !

GEN Flx_factor(GEN f, ulong p)

GEN Flx_factor_squarefree(GEN f, ulong p) returns the squarefree factorization of f modulo p. This is a vector [u_1,...,u_k] of pairwise coprime Flx such that u_k != 1 and f = prod u_i^i. Shallow function.

GEN Flx_mod_Xn1(GEN T, ulong n, ulong p) return T modulo (X^n + 1, p). Shallow function.

GEN Flx_mod_Xnm1(GEN T, ulong n, ulong p) return T modulo (X^n - 1, p). Shallow function.

GEN Flx_degfact(GEN f, ulong p) as FpX_degfact.

GEN Flx_factorff_irred(GEN P, GEN Q, ulong p) as FpX_factorff_irred.

GEN Flx_rootsff(GEN P, GEN T, ulong p) as FpX_rootsff.

GEN Flx_ffisom(GEN P,GEN Q,ulong l) as FpX_ffisom.

### Miscellaneous operations

GEN pol0_Flx(long sv) returns a zero Flx in variable v.

GEN zero_Flx(long sv) alias for pol0_Flx

GEN pol1_Flx(long sv) returns the unit Flx in variable v.

GEN polx_Flx(long sv) returns the variable v as degree 1 Flx.

GEN monomial_Flx(ulong a, long d, long sv) returns the Flx a X^d in variable v.

GEN Flx_normalize(GEN z, ulong p), as FpX_normalize.

GEN Flx_rescale(GEN P, ulong h, ulong p) returns h^{ deg (P)} P(x/h), P is a Flx and h is a non-zero integer.

GEN random_Flx(long d, long sv, ulong p) returns a random Flx in variable v, of degree less than d.

GEN Flx_recip(GEN x), returns the reciprocal polynomial

ulong Flx_resultant(GEN a, GEN b, ulong p), returns the resultant of a and b

ulong Flx_extresultant(GEN a, GEN b, ulong p, GEN *ptU, GEN *ptV) given two Flx a and b, returns their resultant and sets Bezout coefficients (if the resultant is 0, the latter are not set).

GEN Flx_invBarrett(GEN T, ulong p), returns the Barrett inverse M of T defined by M(x) x^n T(1/x) = 1 (mod x^{n-1}) where n is the degree of T.

GEN Flx_renormalize(GEN x, long l), as FpX_renormalize, where l = lg(x), in place.

GEN Flx_shift(GEN T, long n) returns T * x^n if n >= 0, and T \x^{-n} otherwise.

long Flx_val(GEN x) returns the valuation of x, i.e. the multiplicity of the 0 root.

long Flx_valrem(GEN x, GEN *Z) as RgX_valrem, returns the valuation of x. In particular, if the valuation is 0, set *Z to x, not a copy.

GEN Flx_div_by_X_x(GEN A, ulong a, ulong p, ulong *rem), returns the Euclidean quotient of the Flx A by X - a, and sets rem to the remainder  A(a).

ulong Flx_eval(GEN x, ulong y, ulong p), as FpX_eval.

ulong Flx_eval_pre(GEN x, ulong y, ulong p, ulong pi), as Flx_eval, assuming pi is the pseudo inverse of p.

ulong Flx_eval_powers_pre(GEN P, GEN y, ulong p, ulong pi). Let y be the t_VECSMALL (1,a,...,a^n), where n is the degree of the Flx P, return P(a), assuming pi is the pseudo inverse of p.

GEN Flx_Flv_multieval(GEN P, GEN v, ulong p) returns the vector [P(v[1]),...,P(v[n])] as a Flv.

ulong Flx_dotproduct(GEN x, GEN y, ulong p) returns the scalar product of the coefficients of x and y.

GEN Flx_deflate(GEN P, long d) assuming P is a polynomial of the form Q(X^d), return Q.

GEN Flx_splitting(GEN p, long k), as RgX_splitting.

GEN Flx_inflate(GEN P, long d) returns P(X^d).

int Flx_is_squarefree(GEN z, ulong p)

int Flx_is_irred(GEN f, ulong p), as FpX_is_irred.

int Flx_is_smooth(GEN f, long r, ulong p) return 1 if all irreducible factors of f are of degree at most r, 0 otherwise.

long Flx_nbroots(GEN f, ulong p), as FpX_nbroots.

long Flx_nbfact(GEN z, ulong p), as FpX_nbfact.

long Flx_nbfact_Frobenius(GEN f, GEN XP, ulong p), as FpX_nbfact_Frobenius.

GEN Flx_degfact(GEN f, ulong p), as FpX_degfact.

GEN Flx_nbfact_by_degree(GEN z, long *nb, ulong p) Assume that the Flx z is squarefree mod the prime p. Returns a t_VECSMALL D with deg  z entries, such that D[i] is the number of irreducible factors of degree i. Set nb to the total number of irreducible factors (the sum of the D[i]).

void Flx_ffintersect(GEN P,GEN Q, long n, ulong p, GEN*SP, GEN*SQ, GEN MA,GEN MB),\hfil

as FpX_ffintersect

GEN Flv_polint(GEN x, GEN y, ulong p, long sv) as FpV_polint, returning an Flx in variable v.

GEN Flv_Flm_polint(GEN x, GEN V, ulong p, long sv) equivalent (but faster) to applying Flv_polint(x,...) to all the elements of the vector V (thus, returns a FlxV).

GEN Flv_invVandermonde(GEN L, ulong d, ulong p) L being a Flv of length n, return the inverse M of the Vandermonde matrix attached to the elements of L, multiplied by d. If A is a Flv and B = M A, then the polynomial P = sum_{i = 1}^n B[i] X^{i-1} verifies P(L[i]) = d A[i] for 1 <= i <= n.

GEN Flv_roots_to_pol(GEN a, ulong p, long sv) as FpV_roots_to_pol returning an Flx in variable v.

## FlxV

See FpXV operations.

GEN FlxV_Flc_mul(GEN V, GEN W, ulong p), as FpXV_FpC_mul.

GEN FlxV_red(GEN V, ulong p) reduces each components with Flx_red.

GEN FlxV_prod(GEN V, ulong p), V being a vector of Flx, returns their product.

## FlxT

See FpXT operations.

GEN FlxT_red(GEN V, ulong p) reduces each leaf with Flx_red.

## Flxq

See FpXQ operations.

GEN Flxq_add(GEN x, GEN y, GEN T, ulong p)

GEN Flxq_sub(GEN x, GEN y, GEN T, ulong p)

GEN Flxq_mul(GEN x, GEN y, GEN T, ulong p)

GEN Flxq_sqr(GEN y, GEN T, ulong p)

GEN Flxq_inv(GEN x, GEN T, ulong p)

GEN Flxq_invsafe(GEN x, GEN T, ulong p)

GEN Flxq_div(GEN x, GEN y, GEN T, ulong p)

GEN Flxq_pow(GEN x, GEN n, GEN T, ulong p)

GEN Flxq_powu(GEN x, ulong n, GEN T, ulong p)

GEN Flxq_powers(GEN x, long n, GEN T, ulong p)

GEN Flxq_matrix_pow(GEN x, long m, long n, GEN T, ulong p), see FpXQ_matrix_pow.

GEN Flxq_autpow(GEN a, long n, GEN T, ulong p) see FpXQ_autpow.

GEN Flxq_autsum(GEN a, long n, GEN T, GEN p) see FpXQ_autsum.

GEN Flxq_auttrace(GEN a, ulong n, GEN T, ulong p) see FpXQ_auttrace.

GEN Flxq_ffisom_inv(GEN S, GEN T, ulong p), as FpXQ_ffisom_inv.

GEN Flx_Flxq_eval(GEN f, GEN x, GEN T, ulong p) returns f(x).

GEN Flx_FlxqV_eval(GEN f, GEN x, GEN T, ulong p), see FpX_FpXQV_eval.

GEN FlxqV_roots_to_pol(GEN V, GEN T, ulong p, long v) as FqV_roots_to_pol returning an FlxqX in variable v.

int Flxq_issquare(GEN x, GEN T, ulong p) returns 1 if x is a square and 0 otherwise. Assume that T is irreducible mod p.

int Flxq_is2npower(GEN x, long n, GEN T, ulong p) returns 1 if x is a 2^n-th power and 0 otherwise. Assume that T is irreducible mod p.

GEN Flxq_order(GEN a, GEN ord, GEN T, ulong p) as FpXQ_order.

GEN Flxq_log(GEN a, GEN g, GEN ord, GEN T, ulong p) as FpXQ_log

GEN Flxq_sqrtn(GEN x, GEN n, GEN T, ulong p, GEN *zn) as FpXQ_sqrtn.

GEN Flxq_sqrt(GEN x, GEN T, ulong p) returns a square root of x. Return NULL if x is not a square.

GEN Flxq_lroot(GEN a, GEN T, ulong p) returns x such that x^p = a.

GEN Flxq_lroot_fast(GEN a, GEN V, GEN T, ulong p) assuming that V = Flxq_powers(s,p-1,T,p) where s(x)^p = x (mod T(x),p), returns b such that b^p = a. Only useful if p is less than the degree of T.

GEN Flxq_charpoly(GEN x, GEN T, ulong p) returns the characteristic polynomial of x

GEN Flxq_minpoly(GEN x, GEN T, ulong p) returns the minimal polynomial of x

ulong Flxq_norm(GEN x, GEN T, ulong p) returns the norm of x

ulong Flxq_trace(GEN x, GEN T, ulong p) returns the trace of x

GEN Flxq_conjvec(GEN x, GEN T, ulong p) returns the conjugates [x,x^p,x^{p^2},...,x^{p^{n-1}}] where n is the degree of T.

GEN gener_Flxq(GEN T, ulong p, GEN *po) returns a primitive root modulo (T,p). T is an Flx assumed to be irreducible modulo the prime p. If po is not NULL it is set to [o,fa], where o is the order of the multiplicative group of the finite field, and fa is its factorization.

## FlxX

See FpXX operations.

GEN pol1_FlxX(long vX, long sx) returns the unit FlxX as a t_POL in variable vX which only coefficient is pol1_Flx(sx).

GEN polx_FlxX(long vX, long sx) returns the variable X as a degree 1 t_POL with Flx coefficients in the variable x.

long FlxY_degreex(GEN P) return the degree of P with respect to the secondary variable.

GEN FlxX_add(GEN P, GEN Q, ulong p)

GEN FlxX_sub(GEN P, GEN Q, ulong p)

GEN FlxX_Fl_mul(GEN x, ulong y, ulong p)

GEN FlxX_double(GEN x, ulong p)

GEN FlxX_triple(GEN x, ulong p)

GEN FlxX_neg(GEN x, ulong p)

GEN FlxX_Flx_add(GEN y, GEN x, ulong p)

GEN FlxX_Flx_mul(GEN x, GEN y, ulong p)

GEN FlxY_Flx_div(GEN x, GEN y, ulong p) divides the coefficients of x by y using Flx_div.

GEN FlxX_deriv(GEN P, ulong p) returns the derivative of P with respect to the main variable.

GEN FlxY_evalx(GEN P, ulong z, ulong p) P being an FlxY, returns the Flx P(z,Y), where Y is the main variable of P.

GEN FlxY_Flx_translate(GEN P, GEN f, ulong p) P being an FlxY and f being an Flx, return (P(x,Y+f(x)), where Y is the main variable of P.

ulong FlxY_evalx_powers_pre(GEN P, GEN xp, ulong p, ulong pi), xp being the vector [1,x,...,x^n], where n is larger or equal to the degree of P in X, return P(x,Y), where Y is the main variable of Q, assuming pi is the pseudo inverse of p.

ulong FlxY_eval_powers_pre(GEN P, GEN xp, GEN yp, ulong p, ulong pi), xp being the vector [1,x,...,x^n], where n is larger or equal to the degree of P in X and yp being the vector [1,y,...,y^m], where m is larger or equal to the degree of P in Y return P(x,y), assuming pi is the pseudo inverse of p.

GEN FlxY_Flxq_evalx(GEN x, GEN y, GEN T, ulong p) as FpXY_FpXQ_evalx.

GEN FlxY_FlxqV_evalx(GEN x, GEN V, GEN T, ulong p) as FpXY_FpXQV_evalx.

GEN FlxX_renormalize(GEN x, long l), as normalizepol, where l = lg(x), in place.

GEN FlxX_resultant(GEN u, GEN v, ulong p, long sv) Returns Res_X(u, v), which is an Flx. The coefficients of u and v are assumed to be in the variable v.

GEN Flx_FlxY_resultant(GEN a, GEN b, ulong p) Returns Res_x(a, b), which is an Flx in the main variable of b.

GEN FlxX_shift(GEN a, long n)

GEN FlxX_swap(GEN x, long n, long ws), as RgXY_swap.

GEN FlxYqq_pow(GEN x, GEN n, GEN S, GEN T, ulong p), as FpXYQQ_pow.

## FlxqX

See FpXQX operations.

### Preconditioned reduction

For faster reduction, the modulus S can be replaced by an extended modulus, which is an FlxqXT, in all FlxqXQ-classes functions, and in FlxqX_rem and FlxqX_divrem.

GEN FlxqX_get_red(GEN S, GEN T, ulong p) returns the extended modulus eS.

To write code that works both with plain and extended moduli, the following accessors are defined:

GEN get_FlxqX_mod(GEN eS) returns the underlying modulus S.

GEN get_FlxqX_var(GEN eS) returns the variable number of the modulus.

GEN get_FlxqX_degree(GEN eS) returns the degree of the modulus.

### basic functions

GEN random_FlxqX(long d, long v, GEN T, ulong p) returns a random FlxqX in variable v, of degree less than d.

GEN zxX_to_Kronecker(GEN P, GEN Q) assuming P(X,Y) is a polynomial of degree in X strictly less than n, returns P(X,X^{2*n-1}), the Kronecker form of P.

GEN Kronecker_to_FlxqX(GEN z, GEN T, ulong p). Let n =  deg  T and let P(X,Y)\in Z[X,Y] lift a polynomial in K[Y], where K := F_p[X]/(T) and deg _X P < 2n-1 --- such as would result from multiplying minimal degree lifts of two polynomials in K[Y]. Let z = P(t,t^{2*n-1}) be a Kronecker form of P, this function returns Q\in Z[X,t] such that Q is congruent to P(X,t) mod (p, T(X)), deg _X Q < n, and all coefficients are in [0,p[. Not stack-clean. Note that t need not be the same variable as Y!

GEN FlxqX_red(GEN z, GEN T, ulong p)

GEN FlxqX_normalize(GEN z, GEN T, ulong p)

GEN FlxqX_mul(GEN x, GEN y, GEN T, ulong p)

GEN FlxqX_Flxq_mul(GEN P, GEN U, GEN T, ulong p)

GEN FlxqX_Flxq_mul_to_monic(GEN P, GEN U, GEN T, ulong p) returns P*U assuming the result is monic of the same degree as P (in particular U != 0).

GEN FlxqX_sqr(GEN x, GEN T, ulong p)

GEN FlxqX_powu(GEN x, ulong n, GEN T, ulong p)

GEN FlxqX_divrem(GEN x, GEN y, GEN T, ulong p, GEN *pr)

GEN FlxqX_div(GEN x, GEN y, GEN T, ulong p)

GEN FlxqX_rem(GEN x, GEN y, GEN T, ulong p)

GEN FlxqX_invBarrett(GEN T, GEN Q, ulong p)

GEN FlxqX_gcd(GEN x, GEN y, ulong p) returns a (not necessarily monic) greatest common divisor of x and y.

GEN FlxqX_extgcd(GEN x, GEN y, GEN T, ulong p, GEN *ptu, GEN *ptv)

GEN FlxqX_halfgcd(GEN x, GEN y, GEN T, ulong p), see FpX_halfgcd.

GEN FlxqXV_prod(GEN V, GEN T, ulong p)

GEN FlxqX_safegcd(GEN P, GEN Q, GEN T, ulong p) Returns the monic GCD of P and Q if Euclid's algorithm succeeds and NULL otherwise. In particular, if p is not prime or T is not irreducible over F_p[X], the routine may still be used (but will fail if non-invertible leading terms occur).

GEN FlxqX_Frobenius(GEN S, GEN T, GEN p), as FpXQX_Frobenius

GEN FlxqXQ_halfFrobenius(GEN A, GEN S, GEN T, GEN p), as FpXQXQ_halfFrobenius

GEN FlxqX_roots(GEN f, GEN T, ulong p) return the roots of f in F_p[X]/(T). Assumes p is prime and T irreducible in F_p[X].

GEN FlxqX_factor(GEN f, GEN T, ulong p) return the factorization of f over F_p[X]/(T). Assumes p is prime and T irreducible in F_p[X].

long FlxqX_nbroots(GEN S, GEN T, GEN p), as FpX_nbroots.

GEN FlxqX_FlxqXQ_eval(GEN Q, GEN x, GEN S, GEN T, ulong p) as FpX_FpXQ_eval.

GEN FlxqX_FlxqXQV_eval(GEN P, GEN V, GEN S, GEN T, ulong p) as FpX_FpXQV_eval.

## FlxqXQ

See FpXQXQ operations.

GEN FlxqXQ_mul(GEN x, GEN y, GEN S, GEN T, ulong p)

GEN FlxqXQ_sqr(GEN x, GEN S, GEN T, ulong p)

GEN FlxqXQ_inv(GEN x, GEN S, GEN T, ulong p)

GEN FlxqXQ_invsafe(GEN x, GEN S, GEN T, ulong p)

GEN FlxqXQ_div(GEN x, GEN y, GEN S, GEN T, ulong p)

GEN FlxqXQ_pow(GEN x, GEN n, GEN S, GEN T, ulong p)

GEN FlxqXQ_powu(GEN x, ulong n, GEN S, GEN T, ulong p)

GEN FlxqXQ_powers(GEN x, long n, GEN S, GEN T, ulong p)

GEN FlxqXQ_matrix_pow(GEN x, long n, long m, GEN S, GEN T, ulong p)

GEN FlxqXQV_autpow(GEN a, long n, GEN S, GEN T, ulong p) as FpXQXQV_autpow

GEN FlxqXQV_autsum(GEN a, long n, GEN S, GEN T, ulong p) as FpXQXQV_autsum

## F2x

An F2x z is a t_VECSMALL representing a polynomial over F_2[X]. Specifically z[0] is the usual codeword, z[1] = evalvarn(v) for some variable v and the coefficients are given by the bits of remaining words by increasing degree.

### Basic operations

ulong F2x_coeff(GEN x, long i) returns the coefficient i >= 0 of x.

void F2x_clear(GEN x, long i) sets the coefficient i >= 0 of x to 0.

void F2x_flip(GEN x, long i) adds 1 to the coefficient i >= 0 of x.

void F2x_set(GEN x, long i) sets the coefficient i >= 0 of x to 1.

GEN F2x_copy(GEN x)

GEN Flx_to_F2x(GEN x)

GEN Z_to_F2x(GEN x, long v)

GEN ZX_to_F2x(GEN x)

GEN F2v_to_F2x(GEN x, long sv)

GEN F2x_to_Flx(GEN x)

GEN F2x_to_ZX(GEN x)

GEN pol0_F2x(long sv) returns a zero F2x in variable v.

GEN zero_F2x(long sv) alias for pol0_F2x.

GEN pol1_F2x(long sv) returns the F2x in variable v constant to 1.

GEN polx_F2x(long sv) returns the variable v as degree 1 F2x.

GEN monomial_F2x(long d, long sv) returns the F2x X^d in variable v.

GEN random_F2x(long d, long sv) returns a random F2x in variable v, of degree less than d.

long F2x_degree(GEN x) returns the degree of the F2x x. The degree of 0 is defined as -1.

int F2x_equal1(GEN x)

int F2x_equal(GEN x, GEN y)

GEN F2x_1_add(GEN y) returns y+1 where y is a Flx.

GEN F2x_add(GEN x, GEN y)

GEN F2x_mul(GEN x, GEN y)

GEN F2x_sqr(GEN x)

GEN F2x_divrem(GEN x, GEN y, GEN *pr)

GEN F2x_rem(GEN x, GEN y)

GEN F2x_div(GEN x, GEN y)

GEN F2x_renormalize(GEN x, long lx)

GEN F2x_deriv(GEN x)

GEN F2x_deflate(GEN x, long d)

ulong F2x_eval(GEN P, ulong u) returns P(u).

void F2x_shift(GEN x, long d) as RgX_shift

void F2x_even_odd(GEN p, GEN *pe, GEN *po) as RgX_even_odd

long F2x_valrem(GEN x, GEN *Z)

GEN F2x_extgcd(GEN a, GEN b, GEN *ptu, GEN *ptv)

GEN F2x_gcd(GEN a, GEN b)

GEN F2x_halfgcd(GEN a, GEN b)

int F2x_issquare(GEN x) returns 1 if x is a square of a F2x and 0 otherwise.

int F2x_is_irred(GEN f), as FpX_is_irred.

GEN F2x_degfact(GEN f) as FpX_degfact.

GEN F2x_sqrt(GEN x) returns the squareroot of x, assuming x is a square of a F2x.

GEN F2x_Frobenius(GEN T)

GEN F2x_matFrobenius(GEN T)

GEN F2x_factor(GEN f)

GEN F2x_factor_squarefree(GEN f)

## F2xq

See FpXQ operations.

GEN F2xq_mul(GEN x, GEN y, GEN pol)

GEN F2xq_sqr(GEN x,GEN pol)

GEN F2xq_div(GEN x,GEN y,GEN T)

GEN F2xq_inv(GEN x, GEN T)

GEN F2xq_invsafe(GEN x, GEN T)

GEN F2xq_pow(GEN x, GEN n, GEN pol)

GEN F2xq_powu(GEN x, ulong n, GEN pol)

ulong F2xq_trace(GEN x, GEN T)

GEN F2xq_conjvec(GEN x, GEN T) returns the vector of conjugates [x,x^2,x^{2^2},...,x^{2^{n-1}}] where n is the degree of T.

GEN F2xq_log(GEN a, GEN g, GEN ord, GEN T)

GEN F2xq_order(GEN a, GEN ord, GEN T)

GEN F2xq_Artin_Schreier(GEN a, GEN T) returns a solution of x^2+x = a, assuming it exists.

GEN F2xq_sqrt(GEN a, GEN T)

GEN F2xq_sqrt_fast(GEN a, GEN s, GEN T) assuming that s^2 = x (mod T(x)), computes b = a(s) (mod T) so that b^2 = a.

GEN F2xq_sqrtn(GEN a, GEN n, GEN T, GEN *zeta)

GEN gener_F2xq(GEN T, GEN *po)

GEN F2xq_powers(GEN x, long n, GEN T)

GEN F2xq_matrix_pow(GEN x, long m, long n, GEN T)

GEN F2x_F2xq_eval(GEN f, GEN x, GEN T)

GEN F2x_F2xqV_eval(GEN f, GEN x, GEN T), see FpX_FpXQV_eval.

GEN F2xq_autpow(GEN a, long n, GEN T) computes sigma^n(X) assuming a = sigma(X) where sigma is an automorphism of the algebra F_2[X]/T(X).

## F2xqV, F2xqM.

See FqV, FqM operations.

GEN F2xqM_F2xqC_mul(GEN a, GEN b, GEN T)

GEN F2xqM_ker(GEN x, GEN T)

GEN F2xqM_det(GEN a, GEN T)

GEN F2xqM_image(GEN x, GEN T)

GEN F2xqM_inv(GEN a, GEN T)

GEN F2xqM_mul(GEN a, GEN b, GEN T)

long F2xqM_rank(GEN x, GEN T)

GEN matid_F2xqM(long n, GEN T)

## F2xX.

See FpXX operations.

GEN ZXX_to_F2xX(GEN x, long v)

GEN FlxX_to_F2xX(GEN x)

GEN F2xX_to_ZXX(GEN B)

GEN F2xX_renormalize(GEN x, long lx)

long F2xY_degreex(GEN P) return the degree of P with respect to the secondary variable.

GEN pol1_F2xX(long v, long sv)

GEN polx_F2xX(long v, long sv)

GEN F2xX_add(GEN x, GEN y)

GEN F2xX_F2x_mul(GEN x, GEN y)

GEN F2xX_deriv(GEN P) returns the derivative of P with respect to the main variable.

GEN Kronecker_to_F2xqX(GEN z, GEN T)

GEN F2xX_to_Kronecker(GEN z, GEN T)

GEN F2xY_F2xq_evalx(GEN x, GEN y, GEN T) as FpXY_FpXQ_evalx.

GEN F2xY_F2xqV_evalx(GEN x, GEN V, GEN T) as FpXY_FpXQV_evalx.

## F2xXV/F2xXC.

See FpXXV operations.

GEN FlxXC_to_F2xXC(GEN B)

GEN F2xXC_to_ZXXC(GEN B)

## F2xqX.

See FlxqX operations.

GEN random_F2xqX(long d, long v, GEN T, ulong p) returns a random F2xqX in variable v, of degree less than d.

GEN F2xqX_red(GEN z, GEN T)

GEN F2xqX_normalize(GEN z, GEN T)

GEN F2xqX_F2xq_mul(GEN P, GEN U, GEN T)

GEN F2xqX_F2xq_mul_to_monic(GEN P, GEN U, GEN T)

GEN F2xqX_mul(GEN x, GEN y, GEN T)

GEN F2xqX_sqr(GEN x, GEN T)

GEN F2xqX_rem(GEN x, GEN y, GEN T)

GEN F2xqX_div(GEN x, GEN y, GEN T)

GEN F2xqX_divrem(GEN x, GEN y, GEN T, GEN *pr)

GEN F2xqX_gcd(GEN x, GEN y, GEN T)

GEN F2xqX_F2xqXQ_eval(GEN Q, GEN x, GEN S, GEN T) as FpX_FpXQ_eval.

GEN F2xqX_F2xqXQV_eval(GEN P, GEN V, GEN S, GEN T) as FpX_FpXQV_eval.

GEN F2xqX_roots(GEN f, GEN T) return the roots of f in F_2[X]/(T). Assumes T irreducible in F_2[X].

GEN F2xqX_factor(GEN f, GEN T) return the factorisation of f over F_2[X]/(T). Assumes T irreducible in F_2[X].

## F2xqXQ.

See FlxqXQ operations.

GEN F2xqXQ_mul(GEN x, GEN y, GEN S, GEN T)

GEN F2xqXQ_sqr(GEN x, GEN S, GEN T)

GEN F2xqXQ_pow(GEN x, GEN n, GEN S, GEN T)

GEN F2xqXQ_powers(GEN x, long n, GEN S, GEN T)

GEN F2xqXQV_autpow(GEN a, long n, GEN S, GEN T) as FpXQXQV_autpow

GEN F2xqXQV_auttrace(GEN a, long n, GEN S, GEN T). Let sigma be the automorphism defined by sigma(X) = a[1] (mod T(X)) and sigma(Y) = a[2] (mod S(X,Y),T(X)); returns the vector [sigma^n(X),sigma^n(Y),b+sigma(b)+...+sigma^{n-1}(b)] where b = a[3].

## Functions returning objects with t_INTMOD coefficients

Those functions are mostly needed for interface reasons: t_INTMODs should not be used in library mode since the modular kernel is more flexible and more efficient, but GP users do not have access to the modular kernel. We document them for completeness:

GEN Fp_to_mod(GEN z, GEN p), z a t_INT. Returns z * Mod(1,p), normalized. Hence the returned value is a t_INTMOD.

GEN FpX_to_mod(GEN z, GEN p), z a ZX. Returns z * Mod(1,p), normalized. Hence the returned value has t_INTMOD coefficients.

GEN FpC_to_mod(GEN z, GEN p), z a ZC. Returns Col(z) * Mod(1,p), a t_COL with t_INTMOD coefficients.

GEN FpV_to_mod(GEN z, GEN p), z a ZV. Returns Vec(z) * Mod(1,p), a t_VEC with t_INTMOD coefficients.

GEN FpVV_to_mod(GEN z, GEN p), z a ZVV. Returns Vec(z) * Mod(1,p), a t_VEC of t_VEC with t_INTMOD coefficients.

GEN FpM_to_mod(GEN z, GEN p), z a ZM. Returns z * Mod(1,p), with t_INTMOD coefficients.

GEN F2c_to_mod(GEN x)

GEN F2m_to_mod(GEN x)

GEN Flc_to_mod(GEN z)

GEN Flm_to_mod(GEN z)

GEN FpXQC_to_mod(GEN V, GEN T, GEN p) V being a vector of FpXQ, converts each entry to a t_POLMOD with t_INTMOD coefficients, and return a t_COL.

GEN QXQV_to_mod(GEN V, GEN T) V a vector of QXQ, which are lifted representatives of elements of Q[X]/(T) (number field elements in most applications) and T is in Z[X]. Return a vector where all non-rational entries are converted to t_POLMOD modulo T; no reduction mod T is attempted: the representatives should be already reduced. Used to normalize the output of nfroots.

GEN QXQXV_to_mod(GEN V, GEN T) V a vector of polynomials whose coefficients are QXQ. Analogous to QXQV_to_mod. Used to normalize the output of nffactor.

GEN QXQX_to_mod_shallow(GEN z, GEN T) v a polynomial with QXQ coefficients; replace them by mkpolmod(.,T). Shallow function.

The following functions are obsolete and should not be used: they receive a polynomial with arbitrary coefficients, apply RgX_to_FpX, a function from the modular kernel, then *_to_mod:

GEN rootmod(GEN f, GEN p), applies FpX_roots.

GEN rootmod2(GEN f, GEN p), applies ZX_to_flx then Flx_roots_naive.

GEN factmod(GEN f, GEN p) applies FpX_factor.

GEN simplefactmod(GEN f, GEN p) applies FpX_degfact.

## Chinese remainder theorem over Z

GEN Z_chinese(GEN a, GEN b, GEN A, GEN B) returns the integer in [0,  lcm (A,B)[ congruent to a mod A and b mod B, assuming it exists; in other words, that a and b are congruent mod gcd (A,B).

GEN Z_chinese_all(GEN a, GEN b, GEN A, GEN B, GEN *pC) as Z_chinese, setting *pC to the lcm of A and B.

GEN Z_chinese_coprime(GEN a, GEN b, GEN A, GEN B, GEN C), as Z_chinese, assuming that gcd (A,B) = 1 and that C =  lcm (A,B) = AB.

void Z_chinese_pre(GEN A, GEN B, GEN *pC, GEN *pU, GEN *pd) initializes chinese remainder computations modulo A and B. Sets *pC to lcm (A,B), *pd to gcd (A,B), *pU to an integer congruent to 0 mod (A/d) and 1 mod (B/d). It is allowed to set pd = NULL, in which case, d is still computed, but not saved.

GEN Z_chinese_post(GEN a, GEN b, GEN C, GEN U, GEN d) returns the solution to the chinese remainder problem x congruent to a mod A and b mod B, where C, U, d were set in Z_chinese_pre. If d is NULL, assume the problem has a solution. Otherwise, return NULL if it has no solution.

GEN ZV_producttree(GEN x) where x are vectors of integer (or t_VECSMALLs) of length n >= 1, return the vector of t_VECs [f(x),f^2(x),...,f^k(x)] where f is the transformation [a_1,a_2,...,a_m] :--->[a_1 a_2,a_3 a_4,...,a_{m-1} a_m] if m is even and [a_1 a_2,a_3 a4,...,a_{m-2} a_{m-1},a_m] if m is odd, and k is chosen so that f^k(x) is of length 1 (This is the vector [a_1 a_2 ldots a_m]).

GEN ZV_chinese(GEN A, GEN P, GEN *pt_mod) where A and P are vectors of integer (or t_VECSMALLs) of the same length n >= 1, the elements of P being pairwise coprime, and M being the product of the elements of P, returns the integer in [0, M[ congruent to A[i] mod P[i] for all 1 <= i <= n. If pt_mod is not NULL, set *pt_mod to M

GEN ZV_chinese_tree(GEN A, GEN P, GEN T, GEN *pt_mod) as ZV_chinese, where T is assumed to be the tree created by ZV_producttree(P).

GEN ncV_chinese_center(GEN A, GEN P, GEN *pt_mod) where A is a vector of VECSMALLs (seen as vectors of unsigned integers) and P a t_VECSMALL of the same length n >= 1, the elements of P being pairwise coprime, and M being the product of the elements of P, returns the t_COL whose entries are integers in [-M/2, M/2[ congruent to A[i] mod P[i] for all 1 <= i <= n. If pt_mod is not NULL, set *pt_mod to M.

GEN nmV_chinese_center(GEN A, GEN P, GEN *pt_mod) where A is a vector of MATSMALLs (seen as matrices of unsigned integers) and P a t_VECSMALL of the same length n >= 1, the elements of P being pairwise coprime, and M being the product of the elements of P, returns the matrix whose entries are integers in [-M/2, M/2[ congruent to A[i] mod P[i] for all 1 <= i <= n. If pt_mod is not NULL, set *pt_mod to M. NB: this function uses the parallel GP interface.

GEN Z_ZV_mod(GEN A, GEN P) P being a vector of integers of length n >= 1, the elements of P being pairwise coprime, return a vector B of the same length such that B[i] = A (mod P[i]) and 0 <= B[i] < P[i] for all 1 <= i <= n.

GEN Z_nv_mod(GEN A, GEN P) P being a t_VECSMALL of length n >= 1, the elements of P being pairwise coprime, return a t_VECSMALL B of the same length such that B[i] = A (mod P[i]) and 0 <= B[i] < P[i] for all 1 <= i <= n. The entries of P and B are treated as ulongs.

GEN ZX_nv_mod_tree(GEN A, GEN P, GEN T) A being a ZX and P a t_VECSMALL of length n >= 1, the elements of P being pairwise coprime, return the vector of Flx [A (mod P[1]),...,A (mod P[n])], where T is assumed to be the tree created by ZV_producttree(P).

The following pair of functions is used in homomorphic imaging schemes, when reconstructing an integer from its images modulo pairwise coprime integers. The idea is as follows: we want to discover an integer H which satisfies |H| < B for some known bound B; we are given pairs (H_p, p) with H congruent to H_p mod p and all p pairwise coprime.

Given H congruent to H_p modulo a number of p, whose product is q, and a new pair (Hp, p), p coprime to q, the following incremental functions use the chinese remainder theorem (CRT) to find a new H, congruent to the preceding one modulo q, but also to Hp modulo p. It is defined uniquely modulo qp, and we choose the centered representative. When P is larger than 2B, we have H = H, but of course, the value of H may stabilize sooner. In many applications it is possible to directly check that such a partial result is correct.

GEN Z_init_CRT(ulong Hp, ulong p) given a Fl Hp in [0, p-1], returns the centered representative H congruent to Hp modulo p.

int Z_incremental_CRT(GEN *H, ulong Hp, GEN *q, ulong p) given a t_INT *H, centered modulo *q, a new pair (Hp, p) with p coprime to q, this function updates *H so that it also becomes congruent to (Hp, p), and *q to the productqp = p.*q. It returns 1 if the new value is equal to the old one, and 0 otherwise.

GEN chinese1_coprime_Z(GEN v) an alternative divide-and-conquer implementation: v is a vector of t_INTMOD with pairwise coprime moduli. Return the t_INTMOD solving the corresponding chinese remainder problem. This is a streamlined version of

GEN chinese1(GEN v), which solves a general chinese remainder problem (not necessarily over Z, moduli not assumed coprime).

As above, for H a ZM: we assume that H and all Hp have dimension  > 0. The original *H is destroyed.

GEN ZM_init_CRT(GEN Hp, ulong p)

int ZM_incremental_CRT(GEN *H, GEN Hp, GEN *q, ulong p)

As above for H a ZX: note that the degree may increase or decrease. The original *H is destroyed.

GEN ZX_init_CRT(GEN Hp, ulong p, long v)

int ZX_incremental_CRT(GEN *H, GEN Hp, GEN *q, ulong p)

## Rational reconstruction

int Fp_ratlift(GEN x, GEN m, GEN amax, GEN bmax, GEN *a, GEN *b). Assuming that 0 <= x < m, amax >= 0, and bmax > 0 are t_INTs, and that 2 amax bmax < m, attempts to recognize x as a rational a/b, i.e. to find t_INTs a and b such that

@3* a = b x modulo m,

@3* |a| <= amax, 0 < b <= bmax,

@3* gcd (m,b) =  gcd (a,b).

@3If unsuccessful, the routine returns 0 and leaves a, b unchanged; otherwise it returns 1 and sets a and b.

In almost all applications, we actually know that a solution exists, as well as a non-zero multiple B of b, and m = p^ell is a prime power, for a prime p chosen coprime to B hence to b. Under the single assumption gcd (m,b) = 1, if a solution a,b exists satisfying the three conditions above, then it is unique.

GEN FpM_ratlift(GEN M, GEN m, GEN amax, GEN bmax, GEN denom) given an FpM modulo m with reduced or Fp_center-ed entries, reconstructs a matrix with rational coefficients by applying Fp_ratlift to all entries. Assume that all preconditions for Fp_ratlift are satisfied, as well gcd (m,b) = 1 (so that the solution is unique if it exists). Return NULL if the reconstruction fails, and the rational matrix otherwise. If denom is not NULL check further that all denominators divide denom.

The functions is not stack clean if one coefficients of M is negative (centered residues), but still suitable for gerepileupto.

GEN FpX_ratlift(GEN P, GEN m, GEN amax, GEN bmax, GEN denom) as FpM_ratlift, where P is an FpX.

GEN FpC_ratlift(GEN P, GEN m, GEN amax, GEN bmax, GEN denom) as FpM_ratlift, where P is an FpC.

## Zp

GEN Zp_sqrt(GEN b, GEN p, long e) b and p being t_INTs, with p a prime (possibly 2), returns a t_INT a such that a^2 = b mod p^e.

GEN Z2_sqrt(GEN b, long e) b being a t_INTs returns a t_INT a such that a^2 = b mod 2^e.

GEN Zp_sqrtlift(GEN b, GEN a, GEN p, long e) let a,b,p be t_INTs, with p > 1 odd, such that a^2 = b mod p. Returns a t_INT A such that A^2 = b mod p^e. Special case of Zp_sqrtnlift.

GEN Zp_sqrtnlift(GEN b, GEN n, GEN a, GEN p, long e) let a,b,n,p be t_INTs, with n,p > 1, and p coprime to n, such that a^n = b mod p. Returns a t_INT A such that A^n = b mod p^e. Special case of ZpX_liftroot.

GEN Zp_teichmuller(GEN x, GEN p, long e, GEN pe) for p an odd prime, x a t_INT coprime to p, and pe = p^e, returns the (p-1)-th root of 1 congruent to x modulo p, modulo p^e. For convenience, p = 2 is also allowed and we return 1 (x is 1 mod 4) or 2^e - 1 (x is 3 mod 4).

GEN teichmullerinit(long p, long n) returns the values of Zp_teichmuller at all x = 1,..., p-1.

## ZpX

GEN ZpX_roots(GEN f, GEN p, long e) f a ZX with leading term prime to p, and without multiple roots mod p. Return a vector of t_INTs which are the roots of f mod p^e.

GEN ZpX_liftroot(GEN f, GEN a, GEN p, long e) f a ZX with leading term prime to p, and a a root mod p such that v_p(f'(a)) = 0. Return a t_INT which is the root of f mod p^e congruent to a mod p.

GEN ZX_Zp_root(GEN f, GEN a, GEN p, long e) same as ZpX_liftroot without the assumption v_p(f'(a)) = 0. Return a t_VEC of t_INTs, which are the p-adic roots of f congruent to a mod p (given modulo p^e).

GEN ZpX_liftroots(GEN f, GEN S, GEN p, long e) f a ZX with leading term prime to p, and S a vector of simple roots mod p. Return a vector of t_INTs which are the root of f mod p^e congruent to the S[i] mod p.

GEN ZpX_liftfact(GEN A, GEN B, GEN pe, GEN p, long e) is the routine underlying polhensellift. Here, p is prime defines a finite field F_p. A is a polynomial in Z[X], whose leading coefficient is non-zero in F_q. B is a vector of monic FpX, pairwise coprime in F_p[X], whose product is congruent to A/lc(A) in F_p[X]. Lifts the elements of B mod pe = p^e.

GEN ZpX_Frobenius(GEN T, GEN p, ulong e) returns the p-adic lift of the Frobenius automorphism of F_p[X]/(T) to precision e.

long ZpX_disc_val(GEN f, GEN p) returns the valuation at p of the discriminant of f. Assume that f is a monic separable ZX and that p is a prime number. Proceeds by dynamically increasing the p-adic accuracy; infinite loop if the discriminant of f is 0.

long ZpX_resultant_val(GEN f, GEN g, GEN p, long M) returns the valuation at p of Res(f,g). Assume f,g are both ZX, and that p is a prime number coprime to the leading coefficient of f. Proceeds by dynamically increasing the p-adic accuracy. To avoid an infinite loop when the resultant is 0, we return M if the Sylvester matrix mod p^M still does not have maximal rank.

GEN ZpX_gcd(GEN f,GEN g, GEN p, GEN pm) f a monic ZX, g a ZX, pm = p^m a prime power. There is a unique integer r >= 0 and a monic h\in Q_p[X] such that

p^rhZ_p[X] + p^mZ_p[X] = fZ_p[X] + gZ_p[X] + p^mZ_p[X].

Return the 0 polynomial if r >= m and a monic h\inZ[1/p][X] otherwise (whose valuation at p is  > -m).

GEN ZpX_reduced_resultant(GEN f, GEN g, GEN p, GEN pm) f a monic ZX, g a ZX, pm = p^m a prime power. The p-adic reduced resultant\varsidx{resultant (reduced)} of f and g is 0 if f, g not coprime in Z_p[X], and otherwise the generator of the form p^d of

 (fZ_p[X] + gZ_p[X])cap Z_p.

Return the reduced resultant modulo p^m.

GEN ZpX_reduced_resultant_fast(GEN f, GEN g, GEN p, long M) f a monic ZX, g a ZX, p a prime. Returns the p-adic reduced resultant of f and g modulo p^M. This function computes resultants for a sequence of increasing p-adic accuracies (up to M p-adic digits), returning as soon as it obtains a non-zero result. It is very inefficient when the resultant is 0, but otherwise usually more efficient than computations using a priori bounds.

GEN ZpX_monic_factor(GEN f, GEN p, long M) f a monic ZX, p a primer, return the p-adic factorization of f, modulo p^M. This is the underlying low-level recursive function behind factorpadic (using a combination of Round 4 factorization and Hensel lifting); the factors are not sorted and the function is not gerepile-clean.

## ZpXQ

GEN ZpXQ_invlift(GEN b, GEN a, GEN T, GEN p, long e) let p be a prime t_INT and a,b be FpXQs (modulo T) such that a b = 1 mod (p,T). Returns an FpXQ A such that A b = 1 mod (p^e, T). Special case of ZpXQ_liftroot.

GEN ZpXQ_inv(GEN b, GEN T, GEN p, long e) let p be a prime t_INT and b be a FpXQ (modulo T, p^e). Returns an FpXQ A such that A b = 1 mod (p^e, T).

GEN ZpXQ_div(GEN a, GEN b, GEN T, GEN q, GEN p, long e) let p be a prime t_INT and a and b be a FpXQ (modulo T, p^e). Returns an FpXQ c such that c b = a mod (p^e, T). The parameter q must be equal to p^e.

GEN ZpXQ_sqrtnlift(GEN b, GEN n, GEN a, GEN T, GEN p, long e) let n,p be t_INTs, with n,p > 1 and p coprime to n, and a,b be FpXQs (modulo T) such that a^n = b mod (p,T). Returns an Fq A such that A^n = b mod (p^e, T). Special case of ZpXQ_liftroot.

GEN ZpXQ_sqrt(GEN b, GEN T, GEN p, long e) let p being a odd prime and b be a FpXQ (modulo T, p^e), returns a such that a^2 = b mod (p^e, T).

GEN ZpX_ZpXQ_liftroot(GEN f, GEN a, GEN T, GEN p, long e) as ZpXQX_liftroot, but f is a polynomial in Z[X].

GEN ZpX_ZpXQ_liftroot_ea(GEN f, GEN a, GEN T, GEN p, long e, void *E, int early(void *E, GEN x, GEN q)) as ZpX_ZpXQ_liftroot with early abort: the function early(E,x,q) will be called with x is a root of f modulo q = p^n for some n. If early returns a non-zero value, the function returns x immediately.

GEN ZpXQ_log(GEN a, GEN T, GEN p, long e) T being a ZpX irreducible modulo p, return the logarithm of a in Z_p[X]/(T) to precision e, assuming that a = 1 (mod pZ_p[X]) if p odd or a = 1 (mod 4Z_2[X]) if p = 2.

## Zq

GEN Zq_sqrtnlift(GEN b, GEN n, GEN a, GEN T, GEN p, long e)

## ZpXQM

GEN ZpXQM_prodFrobenius(GEN M, GEN T, GEN p, long e) returns the product of matrices M sigma(M) sigma^2(M)...sigma^{n-1}(M) to precision e where sigma is the lift of the Frobenius automorphism over Z_p[X]/(T) and n is the degree of T.

## ZpXQX

GEN ZpXQX_liftfact(GEN A, GEN B, GEN T, GEN pe, GEN p, long e) is the routine underlying polhensellift. Here, p is prime, T(Y) defines a finite field F_q. A is a polynomial in Z[X,Y], whose leading coefficient is non-zero in F_q. B is a vector of monic or FqX, pairwise coprime in F_q[X], whose product is congruent to A/lc(A) in F_q[X]. Lifts the elements of B mod pe = p^e, such that the congruence now holds mod (T,p^e).

GEN ZpXQX_liftroot(GEN f, GEN a, GEN T, GEN p, long e) as ZpX_liftroot, but f is now a polynomial in Z[X,Y] and lift the root a in the unramified extension of Q_p with residue field F_p[Y]/(T), assuming v_p(f(a)) > 0 and v_p(f'(a)) = 0.

GEN ZpXQX_liftroot_vald(GEN f, GEN a, long v, GEN T, GEN p, long e) returns the foots of f as ZpXQX_liftroot, where v is the valuation of the content of f' and it is required that v_p(f(a)) > v and v_p(f'(a)) = v.

GEN ZpXQX_roots(GEN F, GEN T, GEN p, long e)

GEN ZpXQX_divrem(GEN x, GEN Sp, GEN T,GEN q,GEN p,long e, GEN *pr) as FpXQX_divrem. The parameter q must be equal to p^e.

GEN ZpXQX_digits(GEN x, GEN B, GEN T, GEN q, GEN p, long e) As FpXQX_digits. The parameter q must be equal to p^e.

## ZqX

GEN ZqX_roots(GEN F, GEN T, GEN p, long e)

GEN ZqX_liftfact(GEN A, GEN B, GEN T, GEN pe, GEN p, long e)

GEN ZqX_liftroot(GEN f, GEN a, GEN T, GEN p, long e)

## Other p-adic functions

GEN ZpM_echelon(GEN M, long early_abort, GEN p, GEN pm) given a ZM M, a prime p and pm = p^m, returns an echelon form E for M mod p^m. I.e. there exist a square integral matrix U with det  U coprime to p such that E = MU modulo p^m. I early_abort is non-zero, return NULL as soon as one pivot in the echelon form is divisible by p^m. The echelon form is an upper triangular HNF, we do not waste time to reduce it to Gauss-Jordan form.

GEN zlm_echelon(GEN M, long early_abort, ulong p, ulong pm) variant of ZpM_echelon, for a Zlm M.

GEN ZlM_gauss(GEN a, GEN b, ulong p, long e, GEN C) as gauss with the following peculiarities: a and b are ZM, such that a is invertible modulo p. Optional C is an Flm that is an inverse of a mod p or NULL. Return the matrix x such that ax = b mod p^e and all elements of x are in [0,p^e-1]. For efficiency, it is better to reduce a and b mod p^e first.

GEN padic_to_Q(GEN x) truncate the t_PADIC to a t_INT or t_FRAC.

GEN padic_to_Q_shallow(GEN x) shallow version of padic_to_Q

GEN QpV_to_QV(GEN v) apply padic_to_Q_shallow

long padicprec(GEN x, GEN p) returns the absolute p-adic precision of the object x, by definition the minimum precision of the components of x. For a non-zero t_PADIC, this returns valp(x) + precp(x).

long padicprec_relative(GEN x) returns the relative p-adic precision of the t_INT, t_FRAC, or t_PADIC x (minimum precision of the components of x for t_POL or vector/matrices). For a t_PADIC, this returns precp(x) if x != 0, and 0 for x = 0.

### low-level

The following technical function returns an optimal sequence of p-adic accuracies, for a given target accuracy:

ulong quadratic_prec_mask(long n) we want to reach accuracy n >= 1, starting from accuracy 1, using a quadratically convergent, self-correcting, algorithm; in other words, from inputs correct to accuracy l one iteration outputs a result correct to accuracy 2l. For instance, to reach n = 9, we want to use accuracies [1,2,3,5,9] instead of [1,2,4,8,9]. The idea is to essentially double the accuracy at each step, and not overshoot in the end.

Let a_0 = 1, a_1 = 2,..., a_k = n, be the desired sequence of accuracies. To obtain it, we work backwards and set

 a_k = n, a_{i-1} = (a_i + 1)\2.

This is in essence what the function returns. But we do not want to store the a_i explicitly, even as a t_VECSMALL, since this would leave an object on the stack. Instead, we store a_i implicitly in a bitmask MASK: let a_0 = 1, if the i-th bit of the mask is set, set a_{i+1} = 2a_i - 1, and 2a_i otherwise; in short the bits indicate the places where we do something special and do not quite double the accuracy (which would be the straightforward thing to do).

In fact, to avoid returning separately the mask and the sequence length k+1, the function returns MASK + 2^{k+1}, so the highest bit of the mask indicates the length of the sequence, and the following ones give an algorithm to obtain the accuracies. This is much simpler than it sounds, here is what it looks like in practice:

    ulong mask = quadratic_prec_mask(n);
long l = 1;
while (mask > 1) {            /* here, the result is known to accuracy l */
l = 2*l; if (mask & 1) l--; /* new accuracy l for the iteration */
mask >>= 1;                 /* pop low order bit */
/* ... lift to the new accuracy ... */
}
/* we are done. At this point l = n */

@3We just pop the bits in mask starting from the low order bits, stop when mask is 1 (that last bit corresponds to the 2^{k+1} that we added to the mask proper). Note that there is nothing specific to Hensel lifts in that function: it would work equally well for an Archimedean Newton iteration.

Note that in practice, we rather use an infinite loop, and insert an

    if (mask == 1) break;

@3in the middle of the loop: the loop body usually includes preparations for the next iterations (e.g. lifting Bezout coefficients in a quadratic Hensel lift), which are costly and useless in the last iteration.

## Conversions involving single precision objects

### To single precision

ulong Rg_to_Fl(GEN z, ulong p), z which can be mapped to Z/pZ: a t_INT, a t_INTMOD whose modulus is divisible by p, a t_FRAC whose denominator is coprime to p, or a t_PADIC with underlying prime ell satisfying p = ell^n for some n (less than the accuracy of the input). Returns lift(z * Mod(1,p)), normalized, as an Fl.

ulong Rg_to_F2(GEN z), as Rg_to_Fl for p = 2.

ulong padic_to_Fl(GEN x, ulong p) special case of Rg_to_Fl, for a x a t_PADIC.

GEN RgX_to_F2x(GEN x), x a t_POL, returns the F2x obtained by applying Rg_to_Fl coefficientwise.

GEN RgX_to_Flx(GEN x, ulong p), x a t_POL, returns the Flx obtained by applying Rg_to_Fl coefficientwise.

GEN Rg_to_F2xq(GEN z, GEN T), z a GEN which can be mapped to F_2[X]/(T): anything Rg_to_Fl can be applied to, a t_POL to which RgX_to_F2x can be applied to, a t_POLMOD whose modulus is divisible by T (once mapped to a F2x), a suitable t_RFRAC. Returns z as an F2xq, normalized.

GEN Rg_to_Flxq(GEN z, GEN T, ulong p), z a GEN which can be mapped to F_p[X]/(T): anything Rg_to_Fl can be applied to, a t_POL to which RgX_to_Flx can be applied to, a t_POLMOD whose modulus is divisible by T (once mapped to a Flx), a suitable t_RFRAC. Returns z as an Flxq, normalized.

GEN ZX_to_Flx(GEN x, ulong p) reduce ZX x modulo p (yielding an Flx). Faster than RgX_to_Flx.

GEN ZV_to_Flv(GEN x, ulong p) reduce ZV x modulo p (yielding an Flv).

GEN ZXV_to_FlxV(GEN v, ulong p), as ZX_to_Flx, repeatedly called on the vector's coefficients.

GEN ZXT_to_FlxT(GEN v, ulong p), as ZX_to_Flx, repeatedly called on the tree leaves.

GEN ZXX_to_FlxX(GEN B, ulong p, long v), as ZX_to_Flx, repeatedly called on the polynomial's coefficients.

GEN zxX_to_FlxX(GEN z, ulong p) as zx_to_Flx, repeatedly called on the polynomial's coefficients.

GEN ZXXV_to_FlxXV(GEN V, ulong p, long v), as ZXX_to_FlxX, repeatedly called on the vector's coefficients.

GEN ZXXT_to_FlxXT(GEN V, ulong p, long v), as ZXX_to_FlxX, repeatedly called on the tree leaves.

GEN RgV_to_Flv(GEN x, ulong p) reduce the t_VEC/t_COL x modulo p, yielding a t_VECSMALL.

GEN RgM_to_Flm(GEN x, ulong p) reduce the t_MAT x modulo p.

GEN ZM_to_Flm(GEN x, ulong p) reduce ZM x modulo p (yielding an Flm).

GEN ZV_to_zv(GEN z), converts coefficients using itos

GEN ZV_to_nv(GEN z), converts coefficients using itou

GEN ZM_to_zm(GEN z), converts coefficients using itos

GEN FqC_to_FlxC(GEN x, GEN T, GEN p), converts coefficients in Fq to coefficient in Flx, result being a column vector.

GEN FqV_to_FlxV(GEN x, GEN T, GEN p), converts coefficients in Fq to coefficient in Flx, result being a line vector.

GEN FqM_to_FlxM(GEN x, GEN T, GEN p), converts coefficients in Fq to coefficient in Flx.

### From single precision

GEN Flx_to_ZX(GEN z), converts to ZX (t_POL of non-negative t_INTs in this case)

GEN Flx_to_FlxX(GEN z), converts to FlxX (t_POL of constant Flx in this case).

GEN Flx_to_ZX_inplace(GEN z), same as Flx_to_ZX, in place (z is destroyed).

GEN FlxX_to_ZXX(GEN B), converts an FlxX to a polynomial with ZX or t_INT coefficients (repeated calls to Flx_to_ZX).

GEN FlxXC_to_ZXXC(GEN B), converts an FlxXC to a t_COL with ZXX coefficients (repeated calls to FlxX_to_ZXX).

GEN FlxXM_to_ZXXM(GEN B), converts an FlxXM to a t_MAT with ZXX coefficients (repeated calls to FlxX_to_ZXX).

GEN FlxC_to_ZXC(GEN x), converts a vector of Flx to a column vector of polynomials with t_INT coefficients (repeated calls to

Flx_to_ZX).

GEN FlxV_to_ZXV(GEN x), as above but return a t_VEC.

void F2xV_to_FlxV_inplace(GEN v) v is destroyed.

void F2xV_to_ZXV_inplace(GEN v) v is destroyed.

void FlxV_to_ZXV_inplace(GEN v) v is destroyed.

GEN FlxM_to_ZXM(GEN z), converts a matrix of Flx to a matrix of polynomials with t_INT coefficients (repeated calls to Flx_to_ZX).

GEN zx_to_ZX(GEN z), as Flx_to_ZX, without assuming the coefficients to be non-negative.

GEN zx_to_Flx(GEN z, ulong p) as Flx_red without assuming the coefficients to be non-negative.

GEN Flc_to_ZC(GEN z), converts to ZC (t_COL of non-negative t_INTs in this case)

GEN Flv_to_ZV(GEN z), converts to ZV (t_VEC of non-negative t_INTs in this case)

GEN Flm_to_ZM(GEN z), converts to ZM (t_MAT with non-negative t_INTs coefficients in this case)

GEN zc_to_ZC(GEN z) as Flc_to_ZC, without assuming coefficients are non-negative.

GEN zv_to_ZV(GEN z) as Flv_to_ZV, without assuming coefficients are non-negative.

GEN zm_to_ZM(GEN z) as Flm_to_ZM, without assuming coefficients are non-negative.

GEN zv_to_Flv(GEN z, ulong p)

GEN zm_to_Flm(GEN z, ulong p)

### Mixed precision linear algebra Assumes dimensions are compatible.

Multiply a multiprecision object by a single-precision one.

GEN RgM_zc_mul(GEN x, GEN y)

GEN RgMrow_zc_mul(GEN x, GEN y, long i)

GEN RgM_zm_mul(GEN x, GEN y)

GEN RgV_zc_mul(GEN x, GEN y)

GEN RgV_zm_mul(GEN x, GEN y)

GEN ZM_zc_mul(GEN x, GEN y)

GEN zv_ZM_mul(GEN x, GEN y)

GEN ZV_zc_mul(GEN x, GEN y)

GEN ZM_zm_mul(GEN x, GEN y)

GEN ZC_z_mul(GEN x, long y)

GEN ZM_nm_mul(GEN x, GEN y) the entries of y are ulongs.

GEN nm_Z_mul(GEN y, GEN c) the entries of y are ulongs.

### Miscellaneous involving Fl

GEN Fl_to_Flx(ulong x, long evx) converts a unsigned long to a scalar Flx. Assume that evx = evalvarn(vx) for some variable number vx.

GEN Z_to_Flx(GEN x, ulong p, long sv) converts a t_INT to a scalar Flx polynomial. Assume that sv = evalvarn(v) for some variable number v.

GEN Flx_to_Flv(GEN x, long n) converts from Flx to Flv with n components (assumed larger than the number of coefficients of x).

GEN zx_to_zv(GEN x, long n) as Flx_to_Flv.

GEN Flv_to_Flx(GEN x, long sv) converts from vector (coefficient array) to (normalized) polynomial in variable v.

GEN zv_to_zx(GEN x, long n) as Flv_to_Flx.

GEN Flm_to_FlxV(GEN x, long sv) converts the columns of Flm x to an array of Flx in the variable v (repeated calls to Flv_to_Flx).

GEN zm_to_zxV(GEN x, long n) as Flm_to_FlxV.

GEN Flm_to_FlxX(GEN x, long sw, long sv) same as Flm_to_FlxV(x,sv) but returns the result as a (normalized) polynomial in variable w.

GEN FlxV_to_Flm(GEN v, long n) reverse Flm_to_FlxV, to obtain an Flm with n rows (repeated calls to Flx_to_Flv).

GEN FlxX_to_Flm(GEN v, long n) reverse Flm_to_FlxX, to obtain an Flm with n rows (repeated calls to Flx_to_Flv).

GEN FlxX_to_FlxC(GEN B, long n, long sv) see RgX_to_RgV. The coefficients of B are assumed to be in the variable v.

GEN FlxXV_to_FlxM(GEN V, long n, long sv) see RgXV_to_RgM. The coefficients of V[i] are assumed to be in the variable v.

GEN Fly_to_FlxY(GEN a, long sv) convert coefficients of a to constant Flx in variable v.

### Miscellaneous involving F2x

GEN F2x_to_F2v(GEN x, long n) converts from F2x to F2v with n components (assumed larger than the number of coefficients of x).

GEN F2xC_to_ZXC(GEN x), converts a vector of F2x to a column vector of polynomials with t_INT coefficients (repeated calls to F2x_to_ZX).

GEN F2xC_to_FlxC(GEN x)

GEN FlxC_to_F2xC(GEN x)

GEN F2xV_to_F2m(GEN v, long n) F2x_to_F2v to each polynomial to get an F2m with n rows.

# Higher arithmetic over Z: primes, factorization

## Pure powers

long Z_issquare(GEN n) returns 1 if the t_INT n is a square, and 0 otherwise. This is tested first modulo small prime powers, then sqrtremi is called.

long Z_issquareall(GEN n, GEN *sqrtn) as Z_issquare. If n is indeed a square, set sqrtn to its integer square root. Uses a fast congruence test mod 64 x 63 x 65 x 11 before computing an integer square root.

long Z_ispow2(GEN x) returns 1 if the t_INT x is a power of 2, and 0 otherwise.

long uissquare(ulong n) as Z_issquare, for an ulong operand n.

long uissquareall(ulong n, ulong *sqrtn) as Z_issquareall, for an ulong operand n.

ulong usqrt(ulong a) returns the floor of the square root of a.

ulong usqrtn(ulong a, ulong n) returns the floor of the n-th root of a.

long Z_ispower(GEN x, ulong k) returns 1 if the t_INT n is a k-th power, and 0 otherwise; assume that k > 1.

long Z_ispowerall(GEN x, ulong k, GEN *pt) as Z_ispower. If n is indeed a k-th power, set *pt to its integer k-th root.

long Z_isanypower(GEN x, GEN *ptn) returns the maximal k >= 2 such that the t_INT x = n^k is a perfect power, or 0 if no such k exist; in particular ispower(1), ispower(0), ispower(-1) all return 0. If the return value k is not 0 (so that x = n^k) and ptn is not NULL, set *ptn to n.

The following low-level functions are called by Z_isanypower but can be directly useful:

int is_357_power(GEN x, GEN *ptn, ulong *pmask) tests whether the integer x > 0 is a 3-rd, 5-th or 7-th power. The bits of *mask initially indicate which test is to be performed; bit 0: 3-rd, bit 1: 5-th, bit 2: 7-th (e.g. *pmask = 7 performs all tests). They are updated during the call: if the i-th power'' bit is set to 0 then x is not a k-th power. The function returns 0 (not a 3-rd, 5-th or 7-th power), 3 (3-rd power, not a 5-th or 7-th power), 5 (5-th power, not a 7-th power), or 7 (7-th power); if an i-th power bit is initially set to 0, we take it at face value and assume x is not an i-th power without performing any test. If the return value k is non-zero, set *ptn to n such that x = n^k.

int is_pth_power(GEN x, GEN *ptn, forprime_t *T, ulong cutoff) let x > 0 be an integer, cutoff > 0 and T be an iterator over primes  >= 11, we look for the smallest prime p such that x = n^p (advancing T as we go along). The 11 is due to the fact that is_357_power and issquare are faster than the generic version for p < 11.

Fail and return 0 when the existence of p would imply 2^{cutoff} > x^{1/p}, meaning that a possible n is so small that it should have been found by trial division; for maximal speed, you should start by a round of trial division, but the cut-off may also be set to 1 for a rigorous result without any trial division.

Otherwise returns the smallest suitable prime power p^i and set *ptn to the p^i-th root of x (which is now not a p-th power). We may immediately recall the function with the same parameters after setting x = *ptn: it will start at the next prime.

## Factorization

GEN Z_factor(GEN n) factors the t_INT n. The primes'' in the factorization are actually strong pseudoprimes.

GEN absZ_factor(GEN n) returns Z_factor(absi(n)).

long Z_issmooth(GEN n, ulong lim) returns 1 if all the prime factors of the t_INT n are less or equal to lim.

GEN Z_issmooth_fact(GEN n, ulong lim) returns NULL if a prime factor of the t_INT n is  > lim, and returns the factorization of n otherwise, as a t_MAT with t_VECSMALL columns (word-size primes and exponents). Neither memory-clean nor suitable for gerepileupto.

GEN Z_factor_until(GEN n, GEN lim) as Z_factor, but stop the factorization process as soon as the unfactored part is smaller than lim. The resulting factorization matrix only contains the factors found. No other assumptions can be made on the remaining factors.

GEN Z_factor_limit(GEN n, ulong lim) trial divide n by all primes p < lim in the precomputed list of prime numbers and return the corresponding factorization matrix. In this case, the last prime'' divisor in the first column of the factorization matrix may well be a proven composite.

If lim = 0, the effect is the same as setting lim = maxprime() + 1: use all precomputed primes.

GEN absZ_factor_limit(GEN n, ulong all)returns Z_factor_limit(absi(n)).

GEN boundfact(GEN x, ulong lim) as Z_factor_limit, applying to t_INT or t_FRAC inputs.

GEN Z_smoothen(GEN n, GEN L, GEN *pP, GEN *pE) given a t_VECSMALL L containing a list of small primes and a t_INT n, trial divide n by the elements of L and return the cofactor. Return NULL if the cofactor is +- 1. *P and *E contain the list of prime divisors found and their exponents, as t_VECSMALLs. Neither memory-clean, nor suitable for gerepileupto.

GEN Z_factor_listP(GEN N, GEN L) given a t_INT N, a vector or primes L containing all prime divisors of N (and possibly others). Return factor(N). Neither memory-clean, nor suitable for gerepileupto.

GEN factor_pn_1(GEN p, ulong n) returns the factorization of p^n-1, where p is prime and n is a positive integer.

GEN factor_pn_1_limit(GEN p, ulong n, ulong B) returns a partial factorization of p^n-1, where p is prime and n is a positive integer. Don't actively search for prime divisors p > B, but we may find still find some due to Aurifeuillian factorizations. Any entry  > B^2 in the output factorization matrix is a priori not a prime (but may well be).

GEN factor_Aurifeuille_prime(GEN p, long n) an Aurifeuillian factor of phi_n(p), assuming p prime and an Aurifeuillian factor exists (p zeta_n is a square in Q(zeta_n)).

GEN factor_Aurifeuille(GEN a, long d) an Aurifeuillian factor of phi_n(a), assuming a is a non-zero integer and n > 2. Returns 1 if no Aurifeuillian factor exists.

GEN odd_prime_divisors(GEN a) t_VEC of all prime divisors of the t_INT a.

GEN factoru(ulong n), returns the factorization of n. The result is a 2-component vector [P,E], where P and E are t_VECSMALL containing the prime divisors of n, and the v_p(n).

GEN factoru_pow(ulong n), returns the factorization of n. The result is a 3-component vector [P,E,C], where P, E and C are t_VECSMALL containing the prime divisors of n, the v_p(n) and the p^{v_p(n)}.

ulong tridiv_bound(GEN n) returns the trial division bound used by Z_factor(n).

## Coprime factorization

Given a and b two non-zero integers, let ppi(a,b), ppo(a,b), ppg(a,b), pple(a,b) (powers in a of primes inside b, outside b, greater than thos in b, less than or equal to those in b) be the integers defined by

@3* v_p(ppi) = v_p(a) [v_p(b) > 0],

@3* v_p(ppo) = v_p(a) [v_p(b) = 0],

@3* v_p(ppg) = v_p(a) [v_p(a) > v_p(b)],

@3* v_p(pple) = v_p(a) [v_p(a) <= v_p(b)].

GEN Z_ppo(GEN a, GEN b) returns ppo(a,b); shallow function.

ulong u_ppo(ulong a, ulong b) returns ppo(a,b).

GEN Z_ppgle(GEN a, GEN b) returns [ppg(a,b), pple(a,b)]; shallow function.

GEN Z_ppio(GEN a, GEN b) returns [ gcd (a,b), ppi(a,b), ppo(a,b)]; shallow function.

GEN Z_cba(GEN a, GEN b) fast natural coprime base algorithm. Returns a vector of coprime divisors of a and b such that both a and b can be multiplicatively generated from this set.

## Checks attached to arithmetic functions

Arithmetic functions accept arguments of the following kind: a plain positive integer N (t_INT), the factorization fa of a positive integer (a t_MAT with two columns containing respectively primes and exponents), or a vector [N,fa]. A few functions accept non-zero integers (e.g. omega), and some others arbitrary integers (e.g. factorint,...).

int is_Z_factorpos(GEN f) returns 1 if f looks like the factorization of a positive integer, and 0 otherwise. Useful for sanity checks but not 100% foolproof. Specifically, this routine checks that f is a two-column matrix all of whose entries are positive integers. It does not check that entries in the first column (primes'') are prime, or even pairwise coprime, nor that they are stricly increasing.

int is_Z_factornon0(GEN f) returns 1 if f looks like the factorization of a non-zero integer, and 0 otherwise. Useful for sanity checks but not 100% foolproof, analogous to is_Z_factorpos. (Entries in the first column need only be non-zero integers.)

int is_Z_factor(GEN f) returns 1 if f looks like the factorization of an integer, and 0 otherwise. Useful for sanity checks but not 100% foolproof. Specifically, this routine checks that f is a two-column matrix all of whose entries are integers. Entries in the second column (exponents'') are all positive. Either it encodes the factorization'' 0^e, e > 0, or entries in the first column (primes'') are all non-zero.

GEN clean_Z_factor(GEN f) assuming f is the factorization of an integer n, return the factorization of |n|, i.e. remove -1 from the factorization. Shallow function.

GEN fuse_Z_factor(GEN f, GEN B) assuming f is the factorization of an integer n, return boundfact(n, B), i.e. return a factorization where all primary factors for |p| <= B are preserved, and all others are fused'' into a single composite integer; if that remainder is trivial, i.e. equal to 1, it is of course not included. Shallow function.

In the following three routines, f is the name of an arithmetic function, and n a supplied argument. They all raise exceptions if n does not correspond to an integer or an integer factorization of the expected shape.

GEN check_arith_pos(GEN n, const char *f) check whether n is attached to the factorization of a positive integer, and return NULL (plain t_INT) or a factorization extracted from n otherwise. May raise an e_DOMAIN (n <= 0) or an e_TYPE exception (other failures).

GEN check_arith_non0(GEN n, const char *f) check whether n is attached to the factorization of a non-0 integer, and return NULL (plain t_INT) or a factorization extracted from n otherwise. May raise an e_TYPE exception.

GEN check_arith_all(GEN n, const char *f) is attached to the factorization of an integer, and return NULL (plain t_INT) or a factorization extracted from n otherwise.

## Incremental integer factorization

Routines attached to the dynamic factorization of an integer n, iterating over successive prime divisors. This is useful to implement high-level routines allowed to take shortcuts given enough partial information: e.g. moebius(n) can be trivially computed if we hit p such that p^2 | n. For efficiency, trial division by small primes should have already taken place. In any case, the functions below assume that no prime  < 2^{14} divides n.

GEN ifac_start(GEN n, int moebius) schedules a new factorization attempt for the integer n. If moebius is non-zero, the factorization will be aborted as soon as a repeated factor is detected (Moebius mode). The function assumes that n > 1 is a composite t_INT whose prime divisors satisfy p > 2^{14} and that one can write to n in place.

This function stores data on the stack, no gerepile call should delete this data until the factorization is complete. Returns partial, a data structure recording the partial factorization state.

int ifac_next(GEN *partial, GEN *p, long *e) deletes a primary factor p^e from partial and sets p (prime) and e (exponent), and normally returns 1. Whatever remains in the partial structure is now coprime to p.

Returns 0 if all primary factors have been used already, so we are done with the factorization. In this case p is set to NULL. If we ran in Moebius mode and the factorization was in fact aborted, we have e = 1, otherwise e = 0.

int ifac_read(GEN part, GEN *k, long *e) peeks at the next integer to be factored in the list k^e, where k is not necessarily prime and can be a perfect power as well, but will be factored by the next call to ifac_next. You can remove this factorization from the schedule by calling:

void ifac_skip(GEN part) removes the next scheduled factorization.

int ifac_isprime(GEN n) given n whose prime divisors are  > 2^{14}, returns the decision the factoring engine would take about the compositeness of n: 0 if n is a proven composite, and 1 if we believe it to be prime; more precisely, n is a proven prime if factor_proven is set, and only a BPSW-pseudoprime otherwise.

## Integer core, squarefree factorization

long Z_issquarefree(GEN n) returns 1 if the t_INT n is square-free, and 0 otherwise.

long Z_isfundamental(GEN x) returns 1 if the t_INT x is a fundamental discriminant, and 0 otherwise.

GEN core(GEN n) unique squarefree integer d dividing n such that n/d is a square. The core of 0 is defined to be 0.

GEN core2(GEN n) return [d,f] with d squarefree and n = df^2.

GEN corepartial(GEN n, long lim) as core, using boundfact(n,lim) to partially factor n. The result is not necessarily squarefree, but p^2 | n implies p > lim.

GEN core2partial(GEN n, long lim) as core2, using boundfact(n,lim) to partially factor n. The resulting d is not necessarily squarefree, but p^2 | n implies p > lim.

## Primes, primality and compositeness tests

### Chebyshev's pi function, bounds

ulong uprimepi(ulong n), returns the number of primes p <= n (Chebyshev's pi function).

double primepi_upper_bound(double x) return a quick upper bound for pi(x), using Dusart bounds.

GEN gprimepi_upper_bound(GEN x) as primepi_upper_bound, returns a t_REAL.

double primepi_lower_bound(double x) return a quick lower bound for pi(x), using Dusart bounds.

GEN gprimepi_lower_bound(GEN x) as primepi_lower_bound, returns a t_REAL or gen_0.

### Primes, primes in intervals

ulong unextprime(ulong n), returns the smallest prime  >= n. Return 0 if it cannot be represented as an ulong (n bigger than 2^{64} - 59 or 2^{32} - 5 depending on the word size).

ulong uprecprime(ulong n), returns the largest prime  <= n. Return 0 if n <= 1.

ulong uprime(long n) returns the n-th prime, assuming it fits in an ulong (overflow error otherwise).

GEN prime(long n) same as utoi(uprime(n)).

GEN primes_zv(long m) returns the first m primes, in a t_VECSMALL.

GEN primes(long m) return the first m primes, as a t_VEC of t_INTs.

GEN primes_interval(GEN a, GEN b) return the primes in the interval [a,b], as a t_VEC of t_INTs.

GEN primes_interval_zv(ulong a, ulong b) return the primes in the interval [a,b], as a t_VECSMALL of ulongss.

GEN primes_upto_zv(ulong b) return the primes in the interval [2,b], as a t_VECSMALL of ulongss.

### Tests

int uisprime(ulong p), returns 1 if p is a prime number and 0 otherwise.

int uisprime_101(ulong p), assuming that p has no divisor  <= 101, returns 1 if p is a prime number and 0 otherwise.

int uisprime_661(ulong p), assuming that p has no divisor  <= 661, returns 1 if p is a prime number and 0 otherwise.

int isprime(GEN n), returns 1 if the t_INT n is a (fully proven) prime number and 0 otherwise.

long isprimeAPRCL(GEN n), returns 1 if the t_INT n is a prime number and 0 otherwise, using only the APRCL test --- not even trial division or compositeness tests. The workhorse isprime should be faster on average, especially if non-primes are included!

long BPSW_psp(GEN n), returns 1 if the t_INT n is a Baillie-Pomerance-Selfridge-Wagstaff pseudoprime, and 0 otherwise (proven composite).

int BPSW_isprime(GEN x) assuming x is a BPSW-pseudoprime, rigorously prove its primality. The function isprime is currently implemented as

   BPSW_psp(x) && BPSW_isprime(x)

long millerrabin(GEN n, long k) performs k strong Rabin-Miller compositeness tests on the t_INT n, using k random bases. This function also caches square roots of -1 that are encountered during the successive tests and stops as soon as three distinct square roots have been produced; we have in principle factored n at this point, but unfortunately, there is currently no way for the factoring machinery to become aware of it. (It is highly implausible that hard to find factors would be exhibited in this way, though.) This should be slower than BPSW_psp for k >= 4 and we would expect it to be less reliable.

## Iterators over primes

int forprime_init(forprime_t *T, GEN a, GEN b) initialize an iterator T over primes in [a,b]; over primes  >= a if b = NULL. Return 0 if the range is known to be empty from the start (as if b < a or b < 0), and return 1 otherwise.

GEN forprime_next(forprime_t *T) returns the next prime in the range, assuming that T was initialized by forprime_init.

int u_forprime_init(forprime_t *T, ulong a, ulong b)

ulong u_forprime_next(forprime_t *T)

void u_forprime_restrict(forprime_t *T, ulong c) let T an iterator over primes initialized via u_forprime_init(&T, a, b), possibly followed by a number of calls to u_forprime_next, and a <= c <= b. Restrict the range of primes considered to [a,c].

int u_forprime_arith_init(forprime_t *T, ulong a,ulong b, ulong c,ulong q) initialize an iterator over primes in [a,b], congruent to c modulo q. Assume 0 <= c < q and (c,q) = 1. Subsequent calls to u_forprime_next will only return primes congruent to c modulo q.

# Integral, rational and generic linear algebra

## ZC / ZV, ZM

A ZV (resp. a ZM, resp. a ZX) is a t_VEC or t_COL (resp. t_MAT, resp. t_POL) with t_INT coefficients.

### ZC / ZV

void RgV_check_ZV(GEN x, const char *s) Assuming x is a t_VEC or t_COL raise an error if it is not a ZV (s should point to the name of the caller).

int RgV_is_ZV(GEN x) Assuming x is a t_VEC or t_COL return 1 if it is a ZV, and 0 otherwise.

int RgV_is_QV(GEN P) return 1 if the RgV P has only t_INT and t_FRAC coefficients, and 0 otherwise.

int ZV_equal0(GEN x) returns 1 if all entries of the ZV x are zero, and 0 otherwise.

int ZV_cmp(GEN x, GEN y) compare two ZV, which we assume have the same length (lexicographic order, comparing absolute values).

int ZV_abscmp(GEN x, GEN y) compare two ZV, which we assume have the same length (lexicographic order).

int ZV_equal(GEN x, GEN y) returns 1 if the two ZV are equal and 0 otherwise. A t_COL and a t_VEC with the same entries are declared equal.

GEN ZC_add(GEN x, GEN y) adds x and y.

GEN ZC_sub(GEN x, GEN y) subtracts x and y.

GEN ZC_Z_add(GEN x, GEN y) adds y to x[1].

GEN ZC_Z_sub(GEN x, GEN y) subtracts y to x[1].

GEN Z_ZC_sub(GEN a, GEN x) returns the vector [a - x_1, -x_2,...,-x_n].

GEN ZC_copy(GEN x) returns a (t_COL) copy of x.

GEN ZC_neg(GEN x) returns -x as a t_COL.

void ZV_neg_inplace(GEN x) negates the ZV x in place, by replacing each component by its opposite (the type of x remains the same, t_COL or t_COL). If you want to save even more memory by avoiding the implicit component copies, use ZV_togglesign.

void ZV_togglesign(GEN x) negates x in place, by toggling the sign of its integer components. Universal constants gen_1, gen_m1, gen_2 and gen_m2 are handled specially and will not be corrupted. (We use togglesign_safe.)

GEN ZC_Z_mul(GEN x, GEN y) multiplies the ZC or ZV x (which can be a column or row vector) by the t_INT y, returning a ZC.

GEN ZC_Z_divexact(GEN x, GEN y) returns x/y assuming all divisions are exact.

GEN ZC_Z_div(GEN x, GEN y) returns x/y, where the resulting vector has rational entries.

GEN ZV_dotproduct(GEN x,GEN y) as RgV_dotproduct assuming x and y have t_INT entries.

GEN ZV_dotsquare(GEN x) as RgV_dotsquare assuming x has t_INT entries.

GEN ZC_lincomb(GEN u, GEN v, GEN x, GEN y) returns ux + vy, where u, v are t_INT and x,y are ZC or ZV. Return a ZC

void ZC_lincomb1_inplace(GEN X, GEN Y, GEN v) sets X\leftarrow X + vY, where v is a t_INT and X,Y are ZC or ZV. (The result has the type of X.) Memory efficient (e.g. no-op if v = 0), but not gerepile-safe.

GEN ZC_ZV_mul(GEN x, GEN y, GEN p) multiplies the ZC x (seen as a column vector) by the ZV y (seen as a row vector, assumed to have compatible dimensions).

GEN ZV_content(GEN x) returns the GCD of all the components of x.

GEN ZV_extgcd(GEN A) given a vector of n integers A, returns [d, U], where d is the content of A and U is a matrix in GL_n(Z) such that AU = [D,0,...,0].

GEN ZV_prod(GEN x) returns the product of all the components of x (1 for the empty vector).

GEN ZV_sum(GEN x) returns the sum of all the components of x (0 for the empty vector).

long ZV_max_lg(GEN x) returns the effective length of the longest entry in x.

int ZV_dvd(GEN x, GEN y) assuming x, y are two ZVs of the same length, return 1 if y[i] divides x[i] for all i and 0 otherwise. Error if one of the y[i] is 0.

GEN ZV_sort(GEN L) sort the ZV L. Returns a vector with the same type as L.

GEN ZV_sort_uniq(GEN L) sort the ZV L, removing duplicate entries. Returns a vector with the same type as L.

long ZV_search(GEN L, GEN y) look for the t_INT y in the sorted ZV L. Return an index i such that L[i] = y, and 0 otherwise.

GEN ZV_indexsort(GEN L) returns the permutation which, applied to the ZV L, would sort the vector. The result is a t_VECSMALL.

GEN ZV_union_shallow(GEN x, GEN y) given two sorted ZV (as per ZV_sort, returns the union of x and y. Shallow function. In case two entries are equal in x and y, include the one from x.

### ZM

void RgM_check_ZM(GEN A, const char *s) Assuming x is a t_MAT raise an error if it is not a ZM (s should point to the name of the caller).

GEN ZM_copy(GEN x) returns a copy of x.

int ZM_equal(GEN A, GEN B) returns 1 if the two ZM are equal and 0 otherwise.

GEN ZM_add(GEN x, GEN y) returns x + y (assumed to have compatible dimensions).

GEN ZM_sub(GEN x, GEN y) returns x - y (assumed to have compatible dimensions).

GEN ZM_neg(GEN x) returns -x.

void ZM_togglesign(GEN x) negates x in place, by toggling the sign of its integer components. Universal constants gen_1, gen_m1, gen_2 and gen_m2 are handled specially and will not be corrupted. (We use togglesign_safe.)

GEN ZM_mul(GEN x, GEN y) multiplies x and y (assumed to have compatible dimensions).

GEN ZM_sqr(GEN x) returns x^2, where x is a square ZM.

GEN ZM_Z_mul(GEN x, GEN y) multiplies the ZM x by the t_INT y.

GEN ZM_ZC_mul(GEN x, GEN y) multiplies the ZM x by the ZC y (seen as a column vector, assumed to have compatible dimensions).

GEN ZM_diag_mul(GEN d, GEN m) given a vector d with integer entries and a ZM m of compatible dimensions, return diagonal(d) * m.

GEN ZM_mul_diag(GEN m, GEN d) given a vector d with integer entries and a ZM m of compatible dimensions, return m * diagonal(d).

GEN ZM_multosym(GEN x, GEN y)

GEN ZM_transmultosym(GEN x, GEN y)

GEN ZM_transmul(GEN x, GEN y)

GEN ZMrow_ZC_mul(GEN x, GEN y, long i) multiplies the i-th row of ZM x by the ZC y (seen as a column vector, assumed to have compatible dimensions). Assumes that x is non-empty and 0 < i < lg(x[1]).

GEN ZV_ZM_mul(GEN x, GEN y) multiplies the ZV x by the ZM y. Returns a t_VEC.

GEN ZM_Z_divexact(GEN x, GEN y) returns x/y assuming all divisions are exact.

GEN ZM_Z_div(GEN x, GEN y) returns x/y, where the resulting matrix has rational entries.

GEN ZM_pow(GEN x, GEN n) returns x^n, assuming x is a square ZM and n >= 0.

GEN ZM_powu(GEN x, ulong n) returns x^n, assuming x is a square ZM and n >= 0.

GEN ZM_det(GEN M) if M is a ZM, returns the determinant of M. This is the function underlying matdet whenever M is a ZM.

GEN ZM_detmult(GEN M) if M is a ZM, returns a multiple of the determinant of the lattice generated by its columns. This is the function underlying detint.

GEN ZM_supnorm(GEN x) return the sup norm of the ZM x.

GEN ZM_charpoly(GEN M) returns the characteristic polynomial (in variable 0) of the ZM M.

GEN QM_charpoly_ZX(GEN M) returns the characteristic polynomial (in variable 0) of the QM M, assuming that the result has integer coefficients.

GEN QM_charpoly_ZX_bound(GEN M, long b) as QM_charpoly_ZX assuming that the sup norm of the (integral) result is  <= 2^b.

GEN ZM_imagecompl(GEN x) returns matimagecompl(x).

long ZM_rank(GEN x) returns matrank(x).

GEN ZM_indexrank(GEN x) returns matindexrank(x).

GEN ZM_indeximage(GEN x) returns gel(ZM_indexrank(x), 2).

long ZM_max_lg(GEN x) returns the effective length of the longest entry in x.

GEN ZM_inv(GEN M, GEN d) if M is a ZM and d is a t_INT such that M' := dM^{-1} is integral, return M'. It is allowed to set d = NULL, in which case, the determinant of M is used instead.

GEN ZM_inv_ratlift(GEN M, GEN *pd) if M is a ZM, return a primitive matrix H such that M H is d times the identity and set *pd to d. To be used when you expect that the denominator of M^{-1} is much smaller than det  M and no sharp multiplicative bound is available; else use ZM_inv.

GEN QM_inv(GEN M, GEN d) as above, with M a QM. We still assume that M' has integer coefficients.

GEN ZM_det_triangular(GEN x) returns the product of the diagonal entries of x (its determinant if it is indeed triangular).

int ZM_isidentity(GEN x) return 1 if the ZM x is the identity matrix, and 0 otherwise.

int ZM_isscalar(GEN x, GEN s) given a ZM x and a t_INT s, return 1 if x is equal to s times the identity, and 0 otherwise. If s is NULL, test whether x is an arbitrary scalar matrix.

long ZC_is_ei(GEN x) return i if the ZC x has 0 entries, but for a 1 at position i.

int ZM_ishnf(GEN x) return 1 if x is in HNF form, i.e. is upper triangular with positive diagonal coefficients, and for j > i, x_{i,i} > x_{i,j} >= 0.

GEN Qevproj_init(GEN M) let M be a n x d ZM of maximal rank d <= n, representing the basis of a Q-subspace V of Q^n. Return a projector on V, to be used by Qevproj_apply. The interface details may change in the future, but this function currently returns [M, B,D,p], where p is a t_VECSMALL with d entries such that the submatrix A = rowpermute(M,p) is invertible, B is a ZM and d a t_INT such that A B = D  Id _d.

GEN Qevproj_apply(GEN T, GEN pro) let T be an n x n QM, stabilizing a Q-subspace V\subset Q^n of dimension d, and let pro be a projector on that subspace initialized by Qevproj_init(M). Return the d x d matrix representing T_{|V} on the basis given by the columns of M.

GEN Qevproj_apply_vecei(GEN T, GEN pro, long k) as Qevproj_apply, return only the image of the k-th basis vector M[k] (still on the basis given by the columns of M).

## zv, zm

GEN zv_neg(GEN x) return -x. No check for overflow is done, which occurs in the fringe case where an entry is equal to 2^{BIL-1}.

GEN zv_neg_inplace(GEN x) negates x in place and return it. No check for overflow is done, which occurs in the fringe case where an entry is equal to 2^{BIL-1}.

GEN zm_zc_mul(GEN x, GEN y)

GEN zm_mul(GEN x, GEN y)

GEN zv_z_mul(GEN x, long n) return n x. No check for overflow is done.

long zv_content(GEN x) returns the gcd of the entries of x.

long zv_dotproduct(GEN x, GEN y)

long zv_prod(GEN x) returns the product of all the components of x (assumes no overflow occurs).

GEN zv_prod_Z(GEN x) returns the product of all the components of x; consider all x[i] as ulongs.

long zv_sum(GEN x) returns the sum of all the components of x (assumes no overflow occurs).

int zv_cmp0(GEN x) returns 1 if all entries of the zv x are 0, and 0 otherwise.

int zv_equal(GEN x, GEN y) returns 1 if the two zv are equal and 0 otherwise.

int zv_equal0(GEN x) returns 1 if all entries are 0, and return 0 otherwise.

long zv_search(GEN L, long y) look for y in the sorted zv L. Return an index i such that L[i] = y, and 0 otherwise.

GEN zv_copy(GEN x) as Flv_copy.

GEN zm_transpose(GEN x) as Flm_transpose.

GEN zm_copy(GEN x) as Flm_copy.

GEN zero_zm(long m, long n) as zero_Flm.

GEN zero_zv(long n) as zero_Flv.

GEN zm_row(GEN A, long x0) as Flm_row.

int zvV_equal(GEN x, GEN y) returns 1 if the two zvV (vectors of zv) are equal and 0 otherwise.

## ZMV / zmV (vectors of ZM/zm)

int RgV_is_ZMV(GEN x) Assuming x is a t_VEC or t_COL return 1 if its components are ZM, and 0 otherwise.

GEN ZMV_to_zmV(GEN z)

GEN zmV_to_ZMV(GEN z)

GEN ZMV_to_FlmV(GEN z, ulong m)

## RgC / RgV, RgM

RgC and RgV routines assume the inputs are VEC or COL of the same dimension. RgM assume the inputs are MAT of compatible dimensions.

### Matrix arithmetic

void RgM_dimensions(GEN){x, long *m, long *n} sets m, resp. n, to the number of rows, resp. columns of the t_MAT x.

GEN RgC_add(GEN x, GEN y) returns x + y as a t_COL.

GEN RgC_neg(GEN x) returns -x as a t_COL.

GEN RgC_sub(GEN x, GEN y) returns x - y as a t_COL.

GEN RgV_add(GEN x, GEN y) returns x + y as a t_VEC.

GEN RgV_neg(GEN x) returns -x as a t_VEC.

GEN RgV_sub(GEN x, GEN y) returns x - y as a t_VEC.

GEN RgM_add(GEN x, GEN y) return x+y.

GEN RgM_neg(GEN x) returns -x.

GEN RgM_sub(GEN x, GEN y) returns x-y.

GEN RgM_Rg_add(GEN x, GEN y) assuming x is a square matrix and y a scalar, returns the square matrix x + y*Id.

GEN RgM_Rg_add_shallow(GEN x, GEN y) as RgM_Rg_add with much fewer copies. Not suitable for gerepileupto.

GEN RgM_Rg_sub(GEN x, GEN y) assuming x is a square matrix and y a scalar, returns the square matrix x - y*Id.

GEN RgM_Rg_sub_shallow(GEN x, GEN y) as RgM_Rg_sub with much fewer copies. Not suitable for gerepileupto.

GEN RgC_Rg_add(GEN x, GEN y) assuming x is a non-empty column vector and y a scalar, returns the vector [x_1 + y, x_2,...,x_n].

GEN RgC_Rg_sub(GEN x, GEN y) assuming x is a non-empty column vector and y a scalar, returns the vector [x_1 - y, x_2,...,x_n].

GEN Rg_RgC_sub(GEN a, GEN x) assuming x is a non-empty column vector and a a scalar, returns the vector [a - x_1, -x_2,...,-x_n].

GEN RgC_Rg_div(GEN x, GEN y)

GEN RgM_Rg_div(GEN x, GEN y) returns x/y (y treated as a scalar).

GEN RgC_Rg_mul(GEN x, GEN y)

GEN RgV_Rg_mul(GEN x, GEN y)

GEN RgM_Rg_mul(GEN x, GEN y) returns x x y (y treated as a scalar).

GEN RgV_RgC_mul(GEN x, GEN y) returns x x y.

GEN RgV_RgM_mul(GEN x, GEN y) returns x x y.

GEN RgM_RgC_mul(GEN x, GEN y) returns x x y.

GEN RgM_mul(GEN x, GEN y) returns x x y.

GEN RgM_transmul(GEN x, GEN y) returns x~ x y.

GEN RgM_multosym(GEN x, GEN y) returns x x y, assuming the result is a symmetric matrix (about twice faster than a generic matrix multiplication).

GEN RgM_transmultosym(GEN x, GEN y) returns x~ x y, assuming the result is a symmetric matrix (about twice faster than a generic matrix multiplication).

GEN RgMrow_RgC_mul(GEN x, GEN y, long i) multiplies the i-th row of RgM x by the RgC y (seen as a column vector, assumed to have compatible dimensions). Assumes that x is non-empty and 0 < i < lg(x[1]).

GEN RgM_mulreal(GEN x, GEN y) returns the real part of x x y (whose entries are t_INT, t_FRAC, t_REAL or t_COMPLEX).

GEN RgM_sqr(GEN x) returns x^2.

GEN RgC_RgV_mul(GEN x, GEN y) returns x x y (the square matrix (x_iy_j)).

The following two functions are not well defined in general and only provided for convenience in specific cases:

GEN RgC_RgM_mul(GEN x, GEN y) returns x x y[1,] if y is a row matrix 1 x n, error otherwise.

GEN RgM_RgV_mul(GEN x, GEN y) returns x x y[,1] if y is a column matrix n x 1, error otherwise.

GEN RgM_powers(GEN x, long n) returns [x^0, ..., x^n] as a t_VEC of RgMs.

GEN RgV_sum(GEN v) sum of the entries of v

GEN RgV_prod(GEN v) product of the entries of v, using a divide and conquer strategy

GEN RgV_sumpart(GEN v, long n) returns the sum v[1] +...+ v[n] (assumes that lg(v) > n).

GEN RgV_sumpart2(GEN v, long m, long n) returns the sum v[m] +...+ v[n] (assumes that lg(v) > n and m > 0). Returns gen_0 when m > n.

GEN RgM_sumcol(GEN v) returns a t_COL, sum of the columns of the t_MAT v.

GEN RgV_dotproduct(GEN x,GEN y) returns the scalar product of x and y

GEN RgV_dotsquare(GEN x) returns the scalar product of x with itself.

GEN RgV_kill0(GEN v) returns a shallow copy of v where entries matched by gequal0 are replaced by NULL. The return value is not a valid GEN and must be handled specially. The idea is to pre-treat a vector of coefficients to speed up later linear combinations or scalar products.

GEN gram_matrix(GEN v) returns the Gram matrix (v_i.v_j) attached to the entries of v (matrix, or vector of vectors).

GEN RgV_polint(GEN X, GEN Y, long v) X and Y being two vectors of the same length, returns the polynomial T in variable v such that T(X[i]) = Y[i] for all i. The special case X = NULL corresponds to X = [1,2,...,n], where n is the length of Y.

### Special shapes

The following routines check whether matrices or vectors have a special shape, using gequal1 and gequal0 to test components. (This makes a difference when components are inexact.)

int RgV_isscalar(GEN x) return 1 if all the entries of x are 0 (as per gequal0), except possibly the first one. The name comes from vectors expressing polynomials on the standard basis 1,T,..., T^{n-1}, or on nf.zk (whose first element is 1).

int QV_isscalar(GEN x) as RgV_isscalar, assuming x is a QV (t_INT and t_FRAC entries only).

int ZV_isscalar(GEN x) as RgV_isscalar, assuming x is a ZV (t_INT entries only).

int RgM_isscalar(GEN x, GEN s) return 1 if x is the scalar matrix equal to s times the identity, and 0 otherwise. If s is NULL, test whether x is an arbitrary scalar matrix.

int RgM_isidentity(GEN x) return 1 if the t_MAT x is the identity matrix, and 0 otherwise.

int RgM_isdiagonal(GEN x) return 1 if the t_MAT x is a diagonal matrix, and 0 otherwise.

long RgC_is_ei(GEN x) return i if the t_COL x has 0 entries, but for a 1 at position i.

int RgM_is_ZM(GEN x) return 1 if the t_MAT x has only t_INT coefficients, and 0 otherwise.

long RgV_isin(GEN v, GEN x) return the first index i such that v[i] = x if it exists, and 0 otherwise. Naive search in linear time, does not assume that v is sorted.

GEN RgM_diagonal(GEN m) returns the diagonal of m as a t_VEC.

GEN RgM_diagonal_shallow(GEN m) shallow version of RgM_diagonal

### Conversion to floating point entries

GEN RgC_gtofp(GEN x, GEN prec) returns the t_COL obtained by applying gtofp(gel(x,i), prec) to all coefficients of x.

GEN RgC_gtomp(GEN x, long prec) returns the t_COL obtained by applying gtomp(gel(x,i), prec) to all coefficients of x.

GEN RgC_fpnorml2(GEN x, long prec) returns (a stack-clean variant of)

    gnorml2( RgC_gtofp(x, prec) )

GEN RgM_gtofp(GEN x, GEN prec) returns the t_MAT obtained by applying gtofp(gel(x,i), prec) to all coefficients of x.

GEN RgM_gtomp(GEN x, long prec) returns the t_MAT obtained by applying gtomp(gel(x,i), prec) to all coefficients of x.

GEN RgM_fpnorml2(GEN x, long prec) returns (a stack-clean variant of)

    gnorml2( RgM_gtofp(x, prec) )

### Linear algebra, linear systems

GEN RgM_inv(GEN a) returns a left inverse of a (which needs not be square), or NULL if this turns out to be impossible. The latter happens when the matrix does not have maximal rank (or when rounding errors make it appear so).

GEN RgM_inv_upper(GEN a) as RgM_inv, assuming that a is a non-empty invertible upper triangular matrix, hence a little faster.

GEN RgM_RgC_invimage(GEN A, GEN B) returns a t_COL X such that A X = B if one such exists, and NULL otherwise.

GEN RgM_invimage(GEN A, GEN B) returns a t_MAT X such that A X = B if one such exists, and NULL otherwise.

GEN RgM_Hadamard(GEN a) returns a upper bound for the absolute value of det(a). The bound is a t_INT.

GEN RgM_solve(GEN a, GEN b) returns a^{-1}b where a is a square t_MAT and b is a t_COL or t_MAT. Returns NULL if a^{-1} cannot be computed, see RgM_inv.

If b = NULL, the matrix a need no longer be square, and we strive to return a left inverse for a (NULL if it does not exist).

GEN RgM_solve_realimag(GEN M, GEN b) M being a t_MAT with r_1+r_2 rows and r_1+2r_2 columns, y a t_COL or t_MAT such that the equation Mx = y makes sense, returns x under the following simplifying assumptions: the first r_1 rows of M and y are real (the r_2 others are complex), and x is real. This is stabler and faster than calling RgM_solve(M, b) over C. In most applications, M approximates the complex embeddings of an integer basis in a number field, and x is actually rational.

GEN split_realimag(GEN x, long r1, long r2) x is a t_COL or t_MAT with r_1 + r_2 rows, whose first r_1 rows have real entries (the r_2 others are complex). Return an object of the same type as x and r_1 + 2r_2 rows, such that the first r_1 + r_2 rows contain the real part of x, and the r_2 following ones contain the imaginary part of the last r_2 rows of x. Called by RgM_solve_realimag.

GEN RgM_det_triangular(GEN x) returns the product of the diagonal entries of x (its determinant if it is indeed triangular).

GEN Frobeniusform(GEN V, long n) given the vector V of elementary divisors for M - xId, where M is an n x n square matrix. Returns the Frobenius form of M.

int RgM_QR_init(GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec) QR-decomposition of a square invertible t_MAT x with real coefficients. Sets *pB to the vector of squared lengths of the x[i], *pL to the Gram-Schmidt coefficients and *pQ to a vector of successive Householder transforms. If R denotes the transpose of L and Q is the result of applying *pQ to the identity matrix, then x = QR is the QR decomposition of x. Returns 0 is x is not invertible or we hit a precision problem, and 1 otherwise.

int QR_init(GEN x, GEN *pB, GEN *pQ, GEN *pL, long prec) as RgM_QR_init, assuming further that x has t_INT or t_REAL coefficients.

GEN R_from_QR(GEN x, long prec) assuming that x is a square invertible t_MAT with t_INT or t_REAL coefficients, return the upper triangular R from the QR docomposition of x. Not memory clean. If the matrix is not known to have t_INT or t_REAL coefficients, apply RgM_gtomp first.

GEN gaussred_from_QR(GEN x, long prec) assuming that x is a square invertible t_MAT with t_INT or t_REAL coefficients, returns qfgaussred(x~ * x); this is essentially the upper triangular R matrix from the QR decomposition of x, renormalized to accomodate qfgaussred conventions. Not memory clean.

GEN RgM_gram_schmidt(GEN e, GEN *ptB) naive (unstable) Gram-Schmidt orthogonalization of the basis (e_i) given by the columns of t_MAT e. Return the e_i^* (as columns of a t_MAT) and set *ptB to the vector of squared lengths |e_i^*|^2.

GEN RgM_Babai(GEN M, GEN y) given an LLL-reduced t_MAT M and a t_COL y of the same dimension, apply Babai's nearest plane algorithm to return an integral x such that y - Mx has small L_2 norm. This yields an approximate solution to the closest vector problem.

## ZG

Let G be a multiplicative group with neutral element 1_G whose multiplication is supported by gmul and where equality test is performed using gidentical, e.g. a matrix group. The following routines implement basic computations in the group algebra Z[G]. All of them are shallow for efficiency reasons. A ZG is either

@3* a t_INT n, representing n[1_G]

@3* or a factorization matrix'' with two columns [g,e]: the first one contains group elements, sorted according to cmp_universal, and the second one contains integer exponents'', representing sum e_i [g_i].

Note that to_famat and to_famat_shallow(g,e) allow to build the ZG e[g] from e\in Z and g\in G.

GEN ZG_normalize(GEN x) given a t_INT x or a factorization matrix without assuming that the first column is properly sorted. Return a valid (sorted) ZG. Shallow function.

GEN ZG_add(GEN x, GEN y) return x+y; shallow function.

GEN ZG_neg(GEN x) return -x; shallow function.

GEN ZG_sub(GEN x, GEN y) return x-y; shallow function.

GEN ZG_mul(GEN x, GEN y) return xy; shallow function.

GEN ZG_G_mul(GEN x, GEN y) given a ZG x and y\in G, return xy; shallow function.

GEN G_ZG_mul(GEN x, GEN y) given a ZG y and x\in G, return xy; shallow function.

GEN ZG_Z_mul(GEN x, GEN n) given a ZG x and y\in Z, return xy; shallow function.

GEN ZGC_G_mul(GEN v, GEN x) given v a vector of ZG and x\in G return the vector (with the same type as v with entries v[i].x. Shallow function.

void ZGC_G_mul_inplace(GEN v, GEN x) as ZGC_G_mul, modifying v in place.

GEN ZGC_Z_mul(GEN v, GEN n) given v a vector of ZG and n\in Z return the vector (with the same type as v with entries n.v[i]. Shallow function.

GEN G_ZGC_mul(GEN x, GEN v) given v a vector of ZG and x\in G return the vector of x.v[i]. Shallow function.

GEN ZGCs_add(GEN x, GEN y) add two sparse vectors of ZG elements (see Blackbox linear algebra below).

## Blackbox linear algebra

A sparse column zCs v is a t_COL with two components C and E which are t_VECSMALL of the same length, representing sum_i E[i]*e_{C[i]}, where (e_j) is the canonical basis. A sparse matrix (zMs) is a t_VEC of zCs.

FpCs and FpMs are identical to the above, but E[i] is now interpreted as a signed C long integer representing an element of F_p. This is important since p can be so large that p+E[i] would not fit in a C long.

RgCs and RgMs are similar, except that the type of the components of E is now unspecified. Functions handling those later objects must not depend on the type of those components.

It is not possible to derive the space dimension (number of rows) from the above data. Thus most functions take an argument nbrow which is the number of rows of the corresponding column/matrix in dense representation.

GEN zCs_to_ZC(GEN C, long nbrow) convert the sparse vector C to a dense ZC of dimension nbrow.

GEN zMs_to_ZM(GEN M, long nbrow) convert the sparse matrix M to a dense ZM whose columns have dimension nbrow.

GEN FpMs_FpC_mul(GEN M, GEN B, GEN p) multiply the sparse matrix M (over F_p) by the sparse vector B. The result is an FpC, i.e. a dense vector.

GEN zMs_ZC_mul(GEN M, GEN B, GEN p) multiply the sparse matrix M by the sparse vector B (over Z). The result is an ZC, i.e. a dense vector.

GEN FpV_FpMs_mul(GEN B, GEN M, GEN p) multiply the sparse vector B by the sparse matrix M (over F_p). The result is an FpV, i.e. a dense vector.

GEN ZV_zMs_mul(GEN B, GEN M, GEN p) multiply the sparse vector B (over Z) by the sparse matrix M. The result is an ZV, i.e. a dense vector.

void RgMs_structelim(GEN M, long nbrow, GEN A, GEN *p_col, GEN *p_row) M being a RgMs with nbrow rows, A being a list of row indices, Perform structured elimination on M by removing some rows and columns until the number of effectively present rows is equal to the number of columns. the result is stored in two t_VECSMALLs, *p_col and *p_row: *p_col is a map from the new columns indices to the old one. *p_row is a map from the old rows indices to the new one (0 if removed).

GEN FpMs_leftkernel_elt(GEN M, long nbrow, GEN p) M being a sparse matrix over F_p, return a non-zero kbd{FpV} X such that X M components are almost all 0.

GEN FpMs_FpCs_solve(GEN M, GEN B, long nbrow, GEN p) solve the equation M X = B, where M is a sparse matrix and B is a sparse vector, both over F_p. Return either a solution as a t_COL (dense vector), the index of a column which is linearly dependent from the others as a t_VECSMALL with a single component, or NULL (can happen if B is not in the image of M).

GEN FpMs_FpCs_solve_safe(GEN M, GEN B, long nbrow, GEN p) as above, but in the event that p is not a prime and an impossible division occurs, return NULL.

GEN ZpMs_ZpCs_solve(GEN M, GEN B, long nbrow, GEN p, long e) solve the equation MX = B, where M is a sparse matrix and B is a sparse vector, both over Z/p^eZ. Return either a solution as a t_COL (dense vector), or the index of a column which is linearly dependent from the others as a t_VECSMALL with a single component.

GEN gen_FpM_Wiedemann(void *E, GEN (*f)(void*, GEN), GEN B, GEN p) solve the equation f(X) = B over F_p, where B is a FpV, and f is a blackbox endomorphism, where f(E, X) computes the value of f at the (dense) column vector X. Returns either a solution t_COL, or a kernel vector as a t_VEC.

GEN gen_ZpM_Dixon(void *E, GEN (*f)(void*, GEN), GEN B, GEN p, long e) solve equation f(X) = B over Z/p^eZ, where B is a ZV, and f is a blackbox endomorphism, where f(E, X) computes the value of f at the (dense) column vector X. Returns either a solution t_COL, or a kernel vector as a t_VEC.

## Obsolete functions

The functions in this section are kept for backward compatibility only and will eventually disappear.

GEN image2(GEN x) compute the image of x using a very slow algorithm. Use image instead.

# Integral, rational and generic polynomial arithmetic

## ZX

void RgX_check_ZX(GEN x, const char *s) Assuming x is a t_POL raise an error if it is not a ZX (s should point to the name of the caller).

GEN ZX_copy(GEN x,GEN p) returns a copy of x.

long ZX_max_lg(GEN x) returns the effective length of the longest component in x.

GEN scalar_ZX(GEN x, long v) returns the constant ZX in variable v equal to the t_INT x.

GEN scalar_ZX_shallow(GEN x, long v) returns the constant ZX in variable v equal to the t_INT x. Shallow function not suitable for gerepile and friends.

GEN ZX_renormalize(GEN x, long l), as normalizepol, where l = lg(x), in place.

int ZX_equal(GEN x, GEN y) returns 1 if the two ZX have the same degpol and their coefficients are equal. Variable numbers are not checked.

int ZX_equal1(GEN x) returns 1 if the ZX is equal to 1 and 0 otherwise.

GEN ZX_add(GEN x,GEN y) adds x and y.

GEN ZX_sub(GEN x,GEN y) subtracts x and y.

GEN ZX_neg(GEN x,GEN p) returns -x.

GEN ZX_Z_add(GEN x,GEN y) adds the integer y to the ZX x.

GEN ZX_Z_add_shallow(GEN x,GEN y) shallow version of ZX_Z_add.

GEN ZX_Z_sub(GEN x,GEN y) subtracts the integer y to the ZX x.

GEN Z_ZX_sub(GEN x,GEN y) subtracts the ZX y to the integer x.

GEN ZX_Z_mul(GEN x,GEN y) multiplies the ZX x by the integer y.

GEN ZX_mulu(GEN x, ulong y) multiplies x by the integer y.

GEN ZX_shifti(GEN x, long n) shifts all coefficients of x by n bits, which can be negative.

GEN ZX_Z_divexact(GEN x, GEN y) returns x/y assuming all divisions are exact.

GEN ZX_remi2n(GEN x, long n) reduces all coefficients of x to n bits, using remi2n.

GEN ZX_mul(GEN x,GEN y) multiplies x and y.

GEN ZX_sqr(GEN x,GEN p) returns x^2.

GEN ZX_mulspec(GEN a, GEN b, long na, long nb). Internal routine: a and b are arrays of coefficients representing polynomials sum_{i = 0}^{na-1} a[i] X^i and sum_{i = 0}^{nb-1} b[i] X^i. Returns their product (as a true GEN).

GEN ZX_sqrspec(GEN a, long na). Internal routine: a is an array of coefficients representing polynomial sum_{i = 0}^{na-1} a[i] X^i. Return its square (as a true GEN).

GEN ZX_rem(GEN x, GEN y) returns the remainder of the Euclidean division of x mod y. Assume that x, y are two ZX and that y is monic.

GEN ZX_mod_Xnm1(GEN T, ulong n) return T modulo X^n - 1). Shallow function.

GEN ZX_div_by_X_1(GEN T, GEN *r) return the quotient of T by X-1. If r is not NULL set it to T(1).

GEN ZX_gcd(GEN x,GEN y) returns a gcd of the ZX x and y. Not memory-clean, but suitable for gerepileupto.

GEN ZX_gcd_all(GEN x, GEN y, GEN *pX). returns a gcd d of x and y. If pX is not NULL, set *pX to a (non-zero) integer multiple of x/d. If x and y are both monic, then d is monic and *pX is exactly x/d. Not memory clean if the gcd is 1 (in that case *pX is set to x).

GEN ZX_content(GEN x) returns the content of the ZX x.

long ZX_val(GEN P) as RgX_val, but assumes P has t_INT coefficients.

long ZX_valrem(GEN P, GEN *z) as RgX_valrem, but assumes P has t_INT coefficients.

GEN ZX_to_monic(GEN q GEN *L) given q a non-zero ZX, returns a monic integral polynomial Q such that Q(x) = C q(x/L), for some rational C and positive integer L > 0. If L is not NULL, set *L to L; if L = 1, *L is set to gen_1. Not suitable for gerepileupto.

GEN ZX_primitive_to_monic(GEN q, GEN *L) as ZX_to_monic except q is assumed to have trivial content, which avoids recomputing it. The result is suboptimal if q is not primitive (L larger than necessary), but remains correct.

GEN ZX_Z_normalize(GEN q, GEN *L) a restricted version of ZX_primitive_to_monic, where q is a monic ZX of degree  > 0. Finds the largest integer L > 0 such that Q(X) := L^{- deg  q} q(Lx) is integral and return Q; this is not well-defined if q is a monomial, in that case, set L = 1 and Q = q. If L is not NULL, set *L to L.

GEN ZX_Q_normalize(GEN q, GEN *L) a variant of ZX_Z_normalize where L > 0 is allowed to be rational, the monic Q\in Z[X] has possibly smaller coefficients.

long ZX_deflate_order(GEN P) given a non-constant ZX P, returns the largest exponent d such that P is of the form P(x^d).

long ZX_deflate_max(GEN P, long *d). Given a non-constant polynomial with integer coefficients P, sets d to ZX_deflate_order(P) and returns RgX_deflate(P,d). Shallow function.

GEN ZX_rescale(GEN P, GEN h) returns h^{ deg (P)} P(x/h). P is a ZX and h is a non-zero integer. Neither memory-clean nor suitable for gerepileupto.

GEN ZX_rescale2n(GEN P, long n) returns 2^{n deg (P)} P(x >> n) where P is a ZX. Neither memory-clean nor suitable for gerepileupto.

GEN ZX_rescale_lt(GEN P) returns the monic integral polynomial h^{ deg (P)-1} P(x/h), where P is a non-zero ZX and h is its leading coefficient. Neither memory-clean nor suitable for gerepileupto.

GEN ZX_translate(GEN P, GEN c) assume P is a ZX and c an integer. Returns P(X + c) (optimized for c = +- 1).

GEN ZX_unscale(GEN P, GEN h) given a ZX P and a t_INT h, returns P(hx). Not memory clean.

GEN ZX_unscale2n(GEN P, long n) given a ZX P, returns P(x << n). Not memory clean.

GEN ZX_unscale_div(GEN P, GEN h) given a ZX P and a t_INT h such that h | P(0), returns P(hx)/h. Not memory clean.

GEN ZX_eval1(GEN P) returns the integer P(1).

GEN ZX_graeffe(GEN p) returns the Graeffe transform of p, i.e. the ZX q such that p(x)p(-x) = q(x^2).

GEN ZX_deriv(GEN x) returns the derivative of x.

GEN ZX_resultant(GEN A, GEN B) returns the resultant of the ZX A and B.

GEN ZX_disc(GEN T) returns the discriminant of the ZX T.

GEN ZX_factor(GEN T) returns the factorization of the primitive part of T over Q[X] (the content is lost).

int ZX_is_squarefree(GEN T) returns 1 if the ZX T is squarefree, 0 otherwise.

long ZX_is_irred(GEN T) returns 1 it T is irreducible, and 0 otherwise.

GEN ZX_squff(GEN T, GEN *E) write T as a product prod T_i^{e_i} with the e_1 < e_2 < ... all distinct and the T_i pairwise coprime. Return the vector of the T_i, and set *E to the vector of the e_i, as a t_VECSMALL.

GEN ZX_Uspensky(GEN P, GEN ab, long flag, long bitprec) let P be a primitive ZX polynomial whose real roots are simple and bitprec is the relative precision in bits.

@3* If flag is 0 returns a list of intervals that isolate the real roots of P. The return value is a column of elements which are either vectors [a,b] meaning that there is a single root in the open interval (a,b) or elements x0 such that x0 is a root of P. There is no guarantee that all rational roots are found (at most those with denominator a power of 2 can be found and even those are not guaranteed). Beware that the limits of the open intervals can be roots of the polynomial.

@3* If flag is 1 returns an approximation of the real roots of P.

@3* If flag is 2 returns the number of roots.

The argument ab specify the interval in which the roots are searched. The default interval is (- oo , oo ). If ab is an integer or fraction a then the interval is [a, oo ). If ab is a vector [a,b], where t_INT, t_FRAC or t_INFINITY are allowed for a and b, the interval is [a,b].

long ZX_sturm(GEN P) number of real roots of the non-constant squarefree ZX P. For efficiency, it is advised to make P primitive first.

long ZX_sturmpart(GEN P, GEN ab) number of real roots of the non-constant squarefree ZX P in the interval specified by ab: either NULL (no restriction) or a t_VEC [a,b] with two real components (of type t_INT, t_FRAC or t_INFINITY). For efficiency, it is advised to make P primitive first.

## ZXQ

GEN ZXQ_mul(GEN x,GEN y,GEN T) returns x*y mod T, assuming that all inputs are ZXs and that T is monic.

GEN ZXQ_sqr(GEN x,GEN T) returns x^2 mod T, assuming that all inputs are ZXs and that T is monic.

GEN ZXQ_charpoly(GEN A, GEN T, long v): let T and A be ZXs, returns the characteristic polynomial of Mod(A, T). More generally, A is allowed to be a QX, hence possibly has rational coefficients, assuming the result is a ZX, i.e. the algebraic number Mod(A,T) is integral over Z.

GEN ZX_ZXY_resultant(GEN A, GEN B) under the assumption that A in Z[Y], B in Q[Y][X], and R = Res_Y(A, B) \in Z[X], returns the resultant R.

GEN ZX_compositum_disjoint(GEN A, GEN B) given two irreducible ZX defining linearly disjoint extensions, returns a ZX defining their compositum.

GEN ZX_ZXY_rnfequation(GEN A, GEN B, long *lambda), assume A in Z[Y], B in Q[Y][X], and R = Res_Y(A, B) \in Z[X]. If lambda = NULL, returns R as in ZY_ZXY_resultant. Otherwise, lambda must point to some integer, e.g. 0 which is used as a seed. The function then finds a small lambda \in Z (starting from *lambda) such that R_lambda(X) := Res_Y(A, B(X + lambda Y)) is squarefree, resets *lambda to the chosen value and returns R_{lambda}.

## ZXV

GEN ZXV_equal(GEN x,GEN y) returns 1 if the two vectors of ZX are equal, as per ZX_equal (variables are not checked to be equal) and 0 otherwise.

GEN ZXV_Z_mul(GEN x,GEN y) multiplies the vector of ZX x by the integer y.

GEN ZXV_remi2n(GEN x, long n) applies ZX_remi2n to all coefficients of x.

GEN ZXV_dotproduct(GEN x,GEN y) as RgV_dotproduct assuming x and y have ZX entries.

## ZXT

GEN ZXT_remi2n(GEN x, long n) applies ZX_remi2n to all leaves of the tree x.

## ZXX

void RgX_check_ZXX(GEN x, const char *s) Assuming x is a t_POL raise an error if it one of its coefficients is not an integer or a ZX (s should point to the name of the caller).

GEN ZXX_renormalize(GEN x, long l), as normalizepol, where l = lg(x), in place.

long ZXX_max_lg(GEN x) returns the effective length of the longest component in x; assume all coefficients are t_INT or ZXs.

GEN ZXX_Z_mul(GEN x, GEN y) returns x y.

GEN ZXX_Z_add_shallow(GEN x, GEN y) returns x+y. Shallow function.

GEN ZXX_Z_divexact(GEN x, GEN y) returns x/y assuming all integer divisions are exact.

GEN ZXX_to_Kronecker(GEN P, long n) Assuming P(X,Y) is a polynomial of degree in X strictly less than n, returns P(X,X^{2*n-1}), the Kronecker form of P. Shallow function.

GEN ZXX_to_Kronecker_spec(GEN Q, long lQ, long n) return ZXX_to_Kronecker(P, n), where P is the polynomial sum_{i = 0}^{lQ - 1} Q[i] x^i. To be used when splitting the coefficients of genuine polynomials into blocks. Shallow function.

GEN Kronecker_to_ZXX(GEN z, long n, long v) recover P(X,Y) from its Kronecker form P(X,X^{2 n-1}), v is the variable number corresponding to Y. Shallow function.

GEN ZXX_mul_Kronecker(GEN P, GEN Q, long n) return ZX_mul applied to the Kronecker forms P(X,X^{2 n-1}) and Q(X,X^{2 n-1}) of P and Q. Not memory clean.

GEN ZXX_sqr_Kronecker(GEN P, long n) return ZX_sqr applied to the Kronecker forms P(X,X^{2 n-1}) of P. Not memory clean.

## QX

void RgX_check_QX(GEN x, const char *s) Assuming x is a t_POL raise an error if it is not a QX (s should point to the name of the caller).

GEN QX_gcd(GEN x,GEN y) returns a gcd of the QX x and y.

GEN QX_disc(GEN T) returns the discriminant of the QX T.

GEN QX_factor(GEN T) as ZX_factor.

GEN QX_resultant(GEN A, GEN B) returns the resultant of the QX A and B.

GEN QX_complex_roots(GEN p, long l) returns the complex roots of the QX p at accuracy l, where real roots are returned as t_REALs. More efficient when p is irreducible and primitive. Special case of cleanroots.

## QXQ

GEN QXQ_norm(GEN A, GEN B) A being a QX and B being a ZX, returns the norm of the algebraic number A mod B, using a modular algorithm. To ensure that B is a ZX, one may replace it by Q_primpart(B), which of course does not change the norm.

If A is not a ZX --- it has a denominator ---, but the result is nevertheless known to be an integer, it is much more efficient to call QXQ_intnorm instead.

GEN QXQ_intnorm(GEN A, GEN B) A being a QX and B being a ZX, returns the norm of the algebraic number A mod B, assuming that the result is an integer, which is for instance the case is A mod B is an algebraic integer, in particular if A is a ZX. To ensure that B is a ZX, one may replace it by Q_primpart(B) (which of course does not change the norm).

If the result is not known to be an integer, you must use QXQ_norm instead, which is slower.

GEN QXQ_inv(GEN A, GEN B) returns the inverse of A modulo B where A is a QX and B is a ZX. Should you need this for a QX B, just use

    QXQ_inv(A, Q_primpart(B));

@3But in all cases where modular arithmetic modulo B is desired, it is much more efficient to replace B by Q_primpart(B) once and for all.

GEN QXQ_charpoly(GEN A, GEN T, long v) where A is a QX and T is a ZX, returns the characteristic polynomial of Mod(A, T). If the result is known to be a ZX, then calling ZXQ_charpoly will be faster.

GEN QXQ_powers(GEN x, long n, GEN T) returns [x^0,..., x^n] as RgXQ_powers would, but in a more efficient way when x has a huge integer denominator (we start by removing that denominator). Meant to be used to precompute powers of algebraic integers in Q[t]/(T). The current implementation does not require x to be a QX: any polynomial to which Q_remove_denom can be applied is fine.

GEN QXQ_reverse(GEN f, GEN T) as RgXQ_reverse, assuming f is a QX.

GEN QX_ZXQV_eval(GEN f, GEN nV, GEN dV) as RgX_RgXQV_eval, except that f is assumed to be a QX, V is given implicitly by a numerator nV (ZV) and denominator dV (a positive t_INT or NULL for trivial denominator). Not memory clean, but suitable for gerepileupto.

GEN QXV_QXQ_eval(GEN v, GEN a, GEN T) v is a vector of QXs (possibly scalars, i.e. rational numbers, for convenience), a and T both QX. Return the vector of evaluations at a modulo T. Not memory clean, nor suitable for gerepileupto.

GEN QXX_QXQ_eval(GEN P, GEN a, GEN T) P(X,Y) is a t_POL with QX coefficients (possibly scalars, i.e. rational numbers, for convenience) , a and T both QX. Return the QX P(X, a mod T). Not memory clean, nor suitable for gerepileupto.

GEN nfgcd(GEN P, GEN Q, GEN T, GEN den) given P and Q in Z[X,Y], T monic irreducible in Z[Y], returns the primitive d in Z[X,Y] which is a gcd of P, Q in K[X], where K is the number field Q[Y]/(T). If not NULL, den is a multiple of the integral denominator of the (monic) gcd of P,Q in K[X].

GEN nfgcd_all(GEN P, GEN Q, GEN T, GEN den, GEN *Pnew) as nfgcd. If Pnew is not NULL, set *Pnew to a non-zero integer multiple of P/d. If P and Q are both monic, then d is monic and *Pnew is exactly P/d. Not memory clean if the gcd is 1 (in that case *Pnew is set to P).

## zx

GEN zero_zx(long sv) returns a zero zx in variable v.

GEN polx_zx(long sv) returns the variable v as degree 1 Flx.

GEN zx_renormalize(GEN x, long l), as Flx_renormalize, where l = lg(x), in place.

GEN zx_shift(GEN T, long n) returns T multiplied by x^n, assuming n >= 0.

## RgX

### Coefficient ring

long RgX_type(GEN x, GEN *ptp, GEN *ptpol, long *ptprec) returns the natural'' base ring over which the polynomial x is defined. Contrary to what its name suggests, this function also works for scalar types, t_SER and t_MAT x.

Raise an error if it detects consistency problems in modular objects: incompatible rings (e.g. F_p and F_q for primes p != q, F_p[X]/(T) and F_p[X]/(U) for T != U). Minor discrepancies are supported if they make general sense (e.g. F_p and F_{p^k}, but not F_p and Q_p); t_FFELT and t_POLMOD of t_INTMODs are considered inconsistent, even if they define the same field: if you need to use simultaneously these different finite field implementations, multiply the polynomial by a t_FFELT equal to 1 first.

@3* 0: none of the others (presumably multivariate, possibly inconsistent).

@3* t_INT: defined over Q (not necessarily Z).

@3* t_INTMOD: defined over Z/pZ, where *ptp is set to p. It is not checked whether p is prime.

@3* t_COMPLEX: defined over C (at least one t_COMPLEX with at least one inexact floating point t_REAL component). Set *ptprec to the minimal accuracy (as per precision) of inexact components.

@3* t_REAL: defined over R (at least one inexact floating point t_REAL component). Set *ptprec to the minimal accuracy (as per precision) of inexact components.

@3* t_PADIC: defined over Q_p, where *ptp is set to p and *ptprec to the p-adic accuracy.

@3* t_FFELT: defined over a finite field F_{p^k}, where *ptp is set to the field characteristic p and *ptpol is set to a t_FFELT belonging to the field.

@3* other values are composite corresponding to quotients R[X]/(T), with one primary type t1, describing the form of the quotient, and a secondary type t2, describing R. If t is the RgX_type, t1 and t2 are recovered using

void RgX_type_decode(long t, long *t1, long *t2)

t1 is one of

t_POLMOD: at least one t_POLMOD component, set *ppol to the modulus,

t_QUAD: no t_POLMOD, at least one t_QUAD component, set *ppol to the modulus (-.pol) of the t_QUAD,

t_COMPLEX: no t_POLMOD or t_QUAD, at least one t_COMPLEX component, set *ppol to y^2 + 1.

and the underlying base ring R is given by t2, which is one of t_INT, t_INTMOD (set *ptp) or t_PADIC (set *ptp and *ptprec), with the same meaning as above.

int RgX_type_is_composite(long t) t as returned by RgX_type, return 1 if t is a composite type, and 0 otherwise.

GEN RgX_get_0(GEN x) returns 0 in the base ring over which x is defined, to the proper accuracy (e.g. 0, Mod(0,3), O(5^10)).

GEN RgX_get_1(GEN x) returns 1 in the base ring over which x is defined, to the proper accuracy (e.g. 0, Mod(0,3),

### Tests

long RgX_degree(GEN x, long v) x being a t_POL and v >= 0, returns the degree in v of x. Error if x is not a polynomial in v.

int RgX_isscalar(GEN x) return 1 if x all the coefficients of x of degree  > 0 are 0 (as per gequal0).

int RgX_is_rational(GEN P) return 1 if the RgX P has only rational coefficients (t_INT and t_FRAC), and 0 otherwise.

int RgX_is_QX(GEN P) return 1 if the RgX P has only t_INT and t_FRAC coefficients, and 0 otherwise.

int RgX_is_ZX(GEN P) return 1 if the RgX P has only t_INT coefficients, and 0 otherwise.

int RgX_is_monomial(GEN x) returns 1 (true) if x is a non-zero monomial in its main variable, 0 otherwise.

long RgX_equal(GEN x, GEN y) returns 1 if the t_POLs x and y have the same degpol and their coefficients are equal (as per gequal). Variable numbers are not checked. Note that this is more stringent than gequal(x,y), which only checks whether x - y satisfies gequal0; in particular, they may have different apparent degrees provided the extra leading terms are 0.

long RgX_equal_var(GEN x, GEN y) returns 1 if x and y have the same variable number and RgX_equal(x,y) is 1.

### Coefficients, blocks

GEN RgX_coeff(GEN P, long n) return the coefficient of x^n in P, defined as gen_0 if n < 0 or n > degpol(P). Shallow function.

int RgX_blocks(GEN P, long n, long m) writes P(X) = a_0(X)+X^n*a_1(X)*X^n+...+X^{n*(m-1)} a_{m-1}(X), where the a_i are polynomial of degree at most n-1 (except possibly for the last one) and returns [a_0(X),a_1(X),...,a_{m-1}(X)]. Shallow function.

void RgX_even_odd(GEN p, GEN *pe, GEN *po) write p(X) = E(X^2) + X O(X^2) and set *pe = E, *po = O. Shallow function.

GEN RgX_splitting(GEN P, long k) write P(X) = a_0(X^k)+X a_1(X^k)+...+X^{k-1} a_{k-1}(X^k) and return [a_0(X),a_1(X),...,a_{k-1}(X)]. Shallow function.

GEN RgX_copy(GEN x) returns (a deep copy of) x.

GEN RgX_renormalize(GEN x) remove leading terms in x which are equal to (necessarily inexact) zeros.

GEN RgX_renormalize_lg(GEN x, long lx) as setlg(x, lx) followed by RgX_renormalize(x). Assumes that lx <= lg(x).

GEN RgX_recip(GEN P) returns the reverse of the polynomial P, i.e. X^{ deg  P} P(1/X).

GEN RgX_recip_shallow(GEN P) shallow function of RgX_recip.

GEN RgX_deflate(GEN P, long d) assuming P is a polynomial of the form Q(X^d), return Q. Shallow function, not suitable for gerepileupto.

long RgX_deflate_order(GEN P) given a non-constant polynomial P, returns the largest exponent d such that P is of the form P(x^d) (use gequal0 to check whether coefficients are 0).

long RgX_deflate_max(GEN P, long *d) given a non-constant polynomial P, sets d to RgX_deflate_order(P) and returns RgX_deflate(P,d). Shallow function.

GEN RgX_inflate(GEN P, long d) return P(X^d). Shallow function, not suitable for gerepileupto.

### Shifts, valuations

GEN RgX_shift(GEN x, long n) returns x * t^n if n >= 0, and x \t^{-n} otherwise.

GEN RgX_shift_shallow(GEN x, long n) as RgX_shift, but shallow (coefficients are not copied).

GEN RgX_rotate_shallow(GEN P, long k, long p) returns P * X^k (mod X^p-1), assuming the degree of P is strictly less than p, and k >= 0.

void RgX_shift_inplace_init(long v) v >= 0, prepare for a later call to RgX_shift_inplace. Reserves v words on the stack.

GEN RgX_shift_inplace(GEN x, long v) v >= 0, assume that RgX_shift_inplace_init(v) has been called (reserving v words on the stack), immediately followed by a t_POL x. Return RgX_shift(x,v) by shifting x in place. To be used as follows

    RgX_shift_inplace_init(v);
av = avma;
...
x = gerepileupto(av, ...); /* a t_POL */
return RgX_shift_inplace(x, v);

long RgX_valrem(GEN P, GEN *pz) returns the valuation v of the t_POL P with respect to its main variable X. Check whether coefficients are 0 using gequal0. Set *pz to RgX_shift_shallow(P,-v).

long RgX_val(GEN P) returns the valuation v of the t_POL P with respect to its main variable X. Check whether coefficients are 0 using gequal0.

long RgX_valrem_inexact(GEN P, GEN *z) as RgX_valrem, using isexactzero instead of gequal0.

### Basic arithmetic

GEN RgX_add(GEN x,GEN y) adds x and y.

GEN RgX_sub(GEN x,GEN y) subtracts x and y.

GEN RgX_neg(GEN x) returns -x.

GEN RgX_Rg_add(GEN y, GEN x) returns x+y.

GEN RgX_Rg_add_shallow(GEN y, GEN x) returns x+y; shallow function.

GEN Rg_RgX_sub(GEN x, GEN y)

GEN RgX_Rg_sub(GEN y, GEN x) returns x-y

GEN RgX_Rg_mul(GEN y, GEN x) multiplies the RgX y by the scalar x.

GEN RgX_muls(GEN y, long s) multiplies the RgX y by the long s.

GEN RgX_Rg_div(GEN y, GEN x) divides the RgX y by the scalar x.

GEN RgX_divs(GEN y, long s) divides the RgX y by the long s.

GEN RgX_Rg_divexact(GEN x, GEN y) exact division of the RgX y by the scalar x.

GEN RgX_Rg_eval_bk(GEN f, GEN x) returns f(x) using Brent and Kung algorithm. (Use poleval for Horner algorithm.)

GEN RgX_RgV_eval(GEN f, GEN V) as RgX_Rg_eval_bk(f, x), assuming V was output by gpowers(x, n) for some n >= 1.

GEN RgXV_RgV_eval(GEN f, GEN V) apply RgX_RgV_eval_bk(, V) to all the components of the vector f.

GEN RgX_normalize(GEN x) divides x by its leading coefficient. If the latter is 1, x itself is returned, not a copy. Leading coefficients equal to 0 are stripped, e.g.

    0.*t^3 + Mod(0,3)*t^2 + 2*t

@3is normalized to t.

GEN RgX_mul(GEN x, GEN y) multiplies the two t_POL (in the same variable) x and y. Uses Karatsuba algorithm.

GEN RgX_mul_normalized(GEN A, long a, GEN B, long b) returns (X^a + A)(X^b + B) - X^(a+b), where we assume that deg  A < a and deg  B < b are polynomials in the same variable X.

GEN RgX_mulspec(GEN a, GEN b, long na, long nb). Internal routine: a and b are arrays of coefficients representing polynomials sum_{i = 0}^{na-1} a[i] X^i and sum_{i = 0}^{nb-1} b[i] X^i. Returns their product (as a true GEN).

GEN RgX_sqr(GEN x) squares the t_POL x. Uses Karatsuba algorithm.

GEN RgX_sqrspec(GEN a, long na). Internal routine: a is an array of coefficients representing polynomial sum_{i = 0}^{na-1} a[i] X^i. Return its square (as a true GEN).

GEN RgX_divrem(GEN x, GEN y, GEN *r) by default, returns the Euclidean quotient and store the remainder in r. Three special values of r change that behavior * NULL: do not store the remainder, used to implement RgX_div,

@3* ONLY_REM: return the remainder, used to implement RgX_rem,

@3* ONLY_DIVIDES: return the quotient if the division is exact, and NULL otherwise.

GEN RgX_div(GEN x, GEN y)

GEN RgX_div_by_X_x(GEN A, GEN a, GEN *r) returns the quotient of the RgX A by (X - a), and sets r to the remainder A(a).

GEN RgX_rem(GEN x, GEN y)

GEN RgX_pseudodivrem(GEN x, GEN y, GEN *ptr) compute a pseudo-quotient q and pseudo-remainder r such that lc(y)^{ deg (x) -  deg (y) + 1}x = qy + r. Return q and set *ptr to r.

GEN RgX_pseudorem(GEN x, GEN y) return the remainder in the pseudo-division of x by y.

GEN RgXQX_pseudorem(GEN x, GEN y, GEN T) return the remainder in the pseudo-division of x by y over R[X]/(T).

int ZXQX_dvd(GEN x, GEN y, GEN T) let T be a monic irreducible ZX, let x, y be t_POL whose coefficients are either t_INTs or ZX in the same variable as T. Assume further that the leading coefficient of y is an integer. Return 1 if y | x in (Z[Y]/(T))[X], and 0 otherwise.

GEN RgXQX_pseudodivrem(GEN x, GEN y, GEN T, GEN *ptr) compute a pseudo-quotient q and pseudo-remainder r such that lc(y)^{ deg (x) -  deg (y) + 1}x = qy + r in R[X]/(T). Return q and set *ptr to r.

GEN RgX_mulXn(GEN x, long n) returns x * t^n. This may be a t_FRAC if n < 0 and the valuation of x is not large enough.

### GCD, Resultant

GEN RgX_gcd(GEN x, GEN y) returns the GCD of x and y, assumed to be t_POLs in the same variable.

GEN RgX_gcd_simple(GEN x, GEN y) as RgX_gcd using a standard extended Euclidean algorithm. Usually slower than RgX_gcd.

GEN RgX_extgcd(GEN x, GEN y, GEN *u, GEN *v) returns d = GCD(x,y), and sets *u, *v to the Bezout coefficients such that *ux + *vy = d. Uses a generic subresultant algorithm.

GEN RgX_extgcd_simple(GEN x, GEN y, GEN *u, GEN *v) as RgX_extgcd using a standard extended Euclidean algorithm. Usually slower than RgX_extgcd.

GEN RgX_disc(GEN x) returns the discriminant of the t_POL x with respect to its main variable.

GEN RgX_resultant_all(GEN x, GEN y, GEN *sol) returns resultant(x,y). If sol is not NULL, sets it to the last non-constant remainder in the polynomial remainder sequence if it exists and to gen_0 otherwise (e.g. one polynomial has degree 0). Compared to resultant_all, this function always uses the generic subresultant algorithm, hence always computes sol.

### Other operations

GEN RgX_gtofp(GEN x, GEN prec) returns the polynomial obtained by applying

    gtofp(gel(x,i), prec)

@3to all coefficients of x.

GEN RgX_fpnorml2(GEN x, long prec) returns (a stack-clean variant of)

    gnorml2( RgX_gtofp(x, prec) )

GEN RgX_deriv(GEN x) returns the derivative of x with respect to its main variable.

GEN RgX_integ(GEN x) returns the primitive of x vanishing at 0, with respect to its main variable.

GEN RgX_rescale(GEN P, GEN h) returns h^{ deg (P)} P(x/h). P is an RgX and h is non-zero. (Leaves small objects on the stack. Suitable but inefficient for gerepileupto.)

GEN RgX_unscale(GEN P, GEN h) returns P(h x). (Leaves small objects on the stack. Suitable but inefficient for gerepileupto.)

GEN RgXV_unscale(GEN v, GEN h) apply RgX_unscale to a vector of RgX.

GEN RgX_translate(GEN P, GEN c) assume c is a scalar or a polynomials whose main variable has lower priority than the main variable X of P. Returns P(X + c) (optimized for c = +- 1).

GEN RgX_act_Gl2Q(GEN g, long k) let R be a commutative ring and g = [a,b;c,d] be in GL_2(Q), g acts (on the left) on homogeneous polynomials of degree k-2 in V := R[X,Y]_{k-2} via

 g.P := P(dX-cY, -bX+aY) = ( det  g)^{k-2} P((X,Y).g^{-1}).

This function returns the matrix in M_{k-1}(R) of P:--->g.P in the basis (X^{k-2},...,Y^{k-2}) of V.

GEN RgX_act_ZGl2Q(GEN z, long k) let G := GL_2(Q), acting on R[X,Y]_{k-2} and z\in Z[G]. Return the matrix giving P:--->z.P in the basis (X^{k-2},...,Y^{k-2}).

## RgXn

GEN RgXn_red_shallow(GEN x, long n) return x % t^n, where n >= 0. Shallow function.

GEN RgXn_mul(GEN a, GEN b, long n) returns a b modulo X^n, where a,b are two t_POL in the same variable X and n >= 0. Uses Karatsuba algorithm (Mulders, Hanrot-Zimmermann variant).

GEN RgXn_sqr(GEN a, long n) returns a^2 modulo X^n, where a is a t_POL in the variable X and n >= 0. Uses Karatsuba algorithm (Mulders, Hanrot-Zimmermann variant).

GEN RgXn_inv(GEN a, long n) returns a^{-1} modulo X^n, where a is a t_POL in the variable X and n >= 0. Uses Newton-Raphson algorithm.

GEN RgXn_powers(GEN x, long m, long n) returns [x^0, ..., x^m] modulo X^n as a t_VEC of RgXns.

GEN RgXn_powu(GEN x, ulong m, long n) returns x^m modulo X^n.

GEN RgXn_powu_i(GEN x, ulong m, long n) as RgXn_powu, not memory clean.

GEN RgXn_exp(GEN a, long n) returns exp(a) modulo X^n, assuming a = 0 mod X. Uses Hanrot-Zimmermann algorithm.

GEN RgXn_eval(GEN Q, GEN x, long n) special case of RgX_RgXQ_eval, when the modulus is a monomial: returns Q(x) modulo t^n, where x \in R[t].

GEN RgX_RgXn_eval(GEN f, GEN x, long n) returns f(x) modulo X^n.

GEN RgX_RgXnV_eval(GEN f, GEN V, long n) as RgX_RgXn_eval(f, x, n), assuming V was output by RgXn_powers(x, m, n) for some m >= 1.

GEN RgXn_reverse(GEN f, long n) assuming that f = a x mod {x^2} with a invertible, returns a t_POL g of degree  < n such that (g o f)(x) = x modulo x^n.

## RgXnV

GEN RgXnV_red_shallow(GEN x, long n) apply RgXn_red_shallow to all the components of the vector x.

## RgXQ

GEN RgXQ_mul(GEN y, GEN x, GEN T) computes xy mod T

GEN RgXQ_sqr(GEN x, GEN T) computes x^2 mod T

GEN RgXQ_inv(GEN x, GEN T) return the inverse of x mod T.

GEN RgXQ_pow(GEN x, GEN n, GEN T) computes x^n mod T

GEN RgXQ_powu(GEN x, ulong n, GEN T) computes x^n mod T, n being an ulong.

GEN RgXQ_powers(GEN x, long n, GEN T) returns [x^0, ..., x^n] as a t_VEC of RgXQs.

GEN RgXQ_matrix_pow(GEN y, long n, long m, GEN P) returns RgXQ_powers(y,m-1,P), as a matrix of dimension n >=  deg  P.

GEN RgXQ_norm(GEN x, GEN T) returns the norm of Mod(x, T).

GEN RgXQ_charpoly(GEN x, GEN T, long v) returns the characteristic polynomial of Mod(x, T), in variable v.

GEN RgX_RgXQ_eval(GEN f, GEN x, GEN T) returns f(x) modulo T.

GEN RgX_RgXQV_eval(GEN f, GEN V, GEN T) as RgX_RgXQ_eval(f, x, T), assuming V was output by RgXQ_powers(x, n, T) for some n >= 1.

int RgXQ_ratlift(GEN x, GEN T, long amax, long bmax, GEN *P, GEN *Q) Assuming that amax+bmax <  deg  T, attempts to recognize x as a rational function a/b, i.e. to find t_POLs P and Q such that

@3* P = Q x modulo T,

@3* deg  P <= amax, deg  Q <= bmax,

@3* gcd (T,P) =  gcd (P,Q).

@3If unsuccessful, the routine returns 0 and leaves P, Q unchanged; otherwise it returns 1 and sets P and Q.

GEN RgXQ_reverse(GEN f, GEN T) returns a t_POL g of degree  < n = deg T such that T(x) divides (g o f)(x) - x, by solving a linear system. Low-level function underlying modreverse: it returns a lift of \kbd[modreverse(f,T)]; faster than the high-level function since it needs not compute the characteristic polynomial of f mod T (often already known in applications). In the trivial case where n <= 1, returns a scalar, not a constant t_POL.

## RgXQV, RgXQC

GEN RgXQC_red(GEN z, GEN T) z a vector whose coefficients are RgXs (arbitrary GENs in fact), reduce them to RgXQs (applying grem coefficientwise) in a t_COL.

GEN RgXQV_red(GEN z, GEN T) z a t_POL whose coefficients are RgXs (arbitrary GENs in fact), reduce them to RgXQs (applying grem coefficientwise) in a t_VEC.

GEN RgXQV_RgXQ_mul(GEN z, GEN x, GEN T) z multiplies the RgXQV z by the scalar (RgXQ) x.

## RgXQX

GEN RgXQX_red(GEN z, GEN T) z a t_POL whose coefficients are RgXs (arbitrary GENs in fact), reduce them to RgXQs (applying grem coefficientwise).

GEN RgXQX_mul(GEN x, GEN y, GEN T)

GEN RgXQX_RgXQ_mul(GEN x, GEN y, GEN T) multiplies the RgXQX y by the scalar (RgXQ) x.

GEN RgXQX_sqr(GEN x, GEN T)

GEN RgXQX_divrem(GEN x, GEN y, GEN T, GEN *pr)

GEN RgXQX_div(GEN x, GEN y, GEN T, GEN *r)

GEN RgXQX_rem(GEN x, GEN y, GEN T, GEN *r)

GEN RgXQX_translate(GEN P, GEN c, GEN T) assume the main variable X of P has higher priority than the main variable Y of T and c. Return a lift of P(X+Mod(c(Y), T(Y))).

GEN Kronecker_to_mod(GEN z, GEN T) z\in R[X] represents an element P(X,Y) in R[X,Y] mod T(Y) in Kronecker form, i.e. z = P(X,X^{2*n-1})

Let R be some commutative ring, n =  deg  T and let P(X,Y)\in R[X,Y] lift a polynomial in K[Y], where K := R[X]/(T) and deg _X P < 2n-1 --- such as would result from multiplying minimal degree lifts of two polynomials in K[Y]. Let z = P(t,t^{2*n-1}) be a Kronecker form of P, this function returns the image of P(X,t) in K[t], with t_POLMOD coefficients. Not stack-clean. Note that t need not be the same variable as Y!

# NAME

libPARI - Black box algebraic structures

The generic routines like gmul or gadd allow handling objects belonging to a fixed list of basic types, with some natural polymorphism (you can mix rational numbers and polynomials, etc.), at the expense of efficiency and sometimes of clarity when the recursive structure becomes complicated, e.g. a few levels of t_POLMODs attached to different polynomials and variable numbers for quotient structures. This is the only possibility in GP.

On the other hand, the Level 2 Kernel allows dedicated routines to handle efficiently objects of a very specific type, e.g. polynomials with coefficients in the same finite field. This is more efficient, but imvolves a lot of code duplication since polymorphism is no longer possible.

A third and final option, still restricted to library programming, is to define an arbitrary algebraic structure (currently groups, fields, rings, algebras and Z_p-modules) by providing suitable methods, then using generic algorithms. For instance naive Gaussian pivoting applies over all base fields and need only be implemented once. The difference with the first solution is that we no longer depend on the way functions like gmul or gadd will guess what the user is trying to do. We can then implement independently various groups / fields / algebras in a clean way.

# Black box groups

A black box group is defined by a bb_group struct, describing methods available to handle group elements:

      struct bb_group
{
GEN (*mul)(void*, GEN, GEN);
GEN (*pow)(void*, GEN, GEN);
GEN (*rand)(void*);
ulong (*hash)(GEN);
int (*equal)(GEN, GEN);
int (*equal1)(GEN);
GEN (*easylog)(void *E, GEN, GEN, GEN);
};

mul(E,x,y) returns the product x y.

pow(E,x,n) returns x^n (n integer, possibly negative or zero).

rand(E) returns a random element in the group.

hash(x) returns a hash value for x (hash_GEN is suitable for this field).

equal(x,y) returns one if x = y and zero otherwise.

equal1(x) returns one if x is the neutral element in the group, and zero otherwise.

easylog(E,a,g,o) (optional) returns either NULL or the discrete logarithm n such that g^n = a, the element g being of order o. This provides a short-cut in situation where a better algorithm than the generic one is known.

A group is thus described by a struct bb_group as above and auxiliary data typecast to void*. The following functions operate on black box groups:

GEN gen_Shanks_log(GEN x, GEN g, GEN N, void *E, const struct bb_group *grp) \hbadness 10000

Generic baby-step/giant-step algorithm (Shanks's method). Assuming that g has order N, compute an integer k such that g^k = x. Return cgetg(1, t_VEC) if there are no solutions. This requires O( sqrt {N}) group operations and uses an auxiliary table containing O( sqrt {N}) group elements.

The above is useful for a one-shot computation. If many discrete logs are desired: GEN gen_Shanks_init(GEN g, long n, void *E, const struct bb_group *grp) return an auxiliary data structure T required to compute a discrete log in base g. Compute and store all powers g^i, i < n.

GEN gen_Shanks(GEN T, GEN x, ulong N, void *E, const struct bb_group *grp) Let T be computed by gen_Shanks_init(g,n,...). Return k < n N such that g^k = x or NULL if no such index exist. It uses O(N) operation in the group and fast table lookups (in time O( log  n)). The interface is such that the function may be used when the order of the base g is unknown, and hence compute it given only an upper bound B for it: e.g. choose n,N such that nN >= B and compute the discrete log l of g^{-1} in base g, then use gen_order with multiple N = l+1.

GEN gen_Pollard_log(GEN x, GEN g, GEN N, void *E, const struct bb_group *grp) \hbadness 10000

Generic Pollard rho algorithm. Assuming that g has order N, compute an integer k such that g^k = x. This requires O( sqrt {N}) group operations in average and O(1) storage. Will enter an infinite loop if there are no solutions.

GEN gen_plog(GEN x, GEN g, GEN N, void *E, const struct bb_group) Assuming that g has prime order N, compute an integer k such that g^k = x, using either gen_Shanks_log or gen_Pollard_log. Return cgetg(1, t_VEC) if there are no solutions.

GEN gen_Shanks_sqrtn(GEN a, GEN n, GEN N, GEN *zetan, void *E, const struct bb_group *grp) \hbadness 10000 returns one solution of x^n = a in a black box cyclic group of order N. Return NULL if no solution exists. If zetan is not NULL it is set to an element of exact order n. This function uses gen_plog for all prime divisors of gcd (n,N).

GEN gen_PH_log(GEN a, GEN g, GEN N, void *E, const struct bb_group *grp) returns an integer k such that g^k = x, assuming that g has order N, by Pohlig-Hellman algorithm. Return cgetg(1, t_VEC) if there are no solutions. This calls gen_plog repeatedly for all prime divisors p of N.

In the following functions the integer parameter ord can be given in all the formats recognized for the argument of arithmetic functions, i.e. either as a positive t_INT N, or as its factorization matrix faN, or (preferred) as a pair [N,faN].

GEN gen_order(GEN x, GEN ord, void *E, const struct bb_group *grp) computes the order of x; ord is a multiple of the order, for instance the group order.

GEN gen_factored_order(GEN x, GEN ord, void *E, const struct bb_group *grp) returns a pair [o,F], where o is the order of x and F is the factorization of o; ord is as in gen_order.

GEN gen_gener(GEN ord, void *E, const struct bb_group *grp) returns a random generator of the group, assuming it is of order exactly ord.

GEN get_arith_Z(GEN ord) given ord as above in one of the formats recognized for arithmetic functions, i.e. a positive t_INT N, its factorization faN, or the pair [N, faN], return N.

GEN get_arith_ZZM(GEN ord) given ord as above, return the pair [N, faN]. This may require factoring N.

GEN gen_select_order(GEN v, void *E, const struct bb_group *grp) Let v be a vector of possible orders for the group; try to find the true order by checking orders of random points. This will not terminate if there is an ambiguity.

## Black box groups with pairing

Theses functions handle groups of rank at most 2 equipped with a family of bilinear pairings which behave like the Weil pairing on elliptic curves over finite field. In the descriptions below, the function pairorder(E, P, Q, m, F) must return the order of the m-pairing of P and Q, both of order dividing m, where F is the factorisation matrix of a multiple of m.

GEN gen_ellgroup(GEN o, GEN d, GEN *pt_m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)) returns the elementary divisors [d_1, d_2] of the group, assuming it is of order exactly o > 1 (which can be given by a factorization matrix), and that d_2 divides d. If d_2 = 1 then [o] is returned, otherwise m = *pt_m is set to the order of the pairing required to verify a generating set which is to be used with gen_ellgens.

GEN gen_ellgens(GEN d1, GEN d2, GEN m, void *E, const struct bb_group *grp, GEN pairorder(void *E, GEN P, GEN Q, GEN m, GEN F)) the parameters d_1, d_2, m being as returned by gen_ellgroup, returns a pair of generators [P,Q] such that P is of order d_1 and the m-pairing of P and Q is of order m. (Note: Q needs not be of order d_2).

## Functions returning black box groups

const struct bb_group * get_Flxq_star(void **E, GEN T, ulong p)

const struct bb_group * get_FpXQ_star(void **E, GEN T, GEN p) returns a pointer to the black box group (F_p[x]/(T))^*.

const struct bb_group * get_FpE_group(void **pE, GEN a4, GEN a6, GEN p) returns a pointer to a black box group and set *pE to the necessary data for computing in the group E(F_p) where E is the elliptic curve E:y^2 = x^3+a_4 x+a_6, with a_4 and a_6 in F_p.

const struct bb_group * get_FpXQE_group(void **pE, GEN a4, GEN a6, GEN T, GEN p) returns a pointer to a black box group and set *pE to the necessary data for computing in the group E(F_p[X]/(T)) where E is the elliptic curve E:y^2 = x^3+a_4 x+a_6, with a_4 and a_6 in F_p[X]/(T).

const struct bb_group * get_FlxqE_group(void **pE, GEN a4, GEN a6, GEN T, ulong p) idem for small p.

const struct bb_group * get_F2xqE_group(void **pE, GEN a2, GEN a6, GEN T) idem for p = 2.

# Black box finite fields

A black box finite field is defined by a bb_field struct, describing methods available to handle field elements:

    struct bb_field
{
GEN (*red)(void *E ,GEN);
GEN (*mul)(void *E ,GEN, GEN);
GEN (*neg)(void *E ,GEN);
GEN (*inv)(void *E ,GEN);
int (*equal0)(GEN);
GEN (*s)(void *E, long);
};

@3In contrast of black box group, elements can have non canonical forms, and only red is required to return a canonical form.

red(E,x) returns the canonical form of x.

add(E,x,y) returns the sum x+y.

mul(E,x,y) returns the product x y.

neg(E,x) returns -x.

inv(E,x) returns the inverse of x.

equal0(x) x being in canonical form, returns one if x = 0 and zero otherwise.

s(n) n being a small signed integer, returns n times the unit element.

@3A finite field is thus described by a struct bb_field as above and auxiliary data typecast to void*. The following functions operate on black box fields:

GEN gen_Gauss(GEN a, GEN b, void *E, const struct bb_field *ff)

GEN gen_Gauss_pivot(GEN x, long *rr, void *E, const struct bb_field *ff)

GEN gen_det(GEN a, void *E, const struct bb_field *ff)

GEN gen_ker(GEN x, long deplin, void *E, const struct bb_field *ff)

GEN gen_matcolmul(GEN a, GEN b, void *E, const struct bb_field *ff)

GEN gen_matid(long n, void *E, const struct bb_field *ff)

GEN gen_matmul(GEN a, GEN b, void *E, const struct bb_field *ff)

## Functions returning black box fields

const struct bb_field * get_Fp_field(void **pE, GEN p)

const struct bb_field * get_Fq_field(void **pE, GEN T, GEN p)

const struct bb_field * get_Flxq_field(void **pE, GEN T, ulong p)

const struct bb_field * get_F2xq_field(void **pE, GEN T)

const struct bb_field * get_nf_field(void **pE, GEN nf)

# Black box algebra

A black box algebra is defined by a bb_algebra struct, describing methods available to handle algebra elements:

  struct bb_algebra
{
GEN (*red)(void *E, GEN x);
GEN (*add)(void *E, GEN x, GEN y);
GEN (*sub)(void *E, GEN x, GEN y);
GEN (*mul)(void *E, GEN x, GEN y);
GEN (*sqr)(void *E, GEN x);
GEN (*one)(void *E);
GEN (*zero)(void *E);
};

@3In contrast with black box groups, elements can have non canonical forms, but only add is allowed to return a non canonical form.

red(E,x) returns the canonical form of x.

add(E,x,y) returns the sum x+y.

sub(E,x,y) returns the difference x-y.

mul(E,x,y) returns the product x y.

sqr(E,x) returns the square x^2.

one(E) returns the unit element.

zero(E) returns the zero element.

@3An algebra is thus described by a struct bb_algebra as above and auxiliary data typecast to void*. The following functions operate on black box algebra:

GEN gen_bkeval(GEN P, long d, GEN x, int use_sqr, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)) x being an element of the black box algebra, and P some black box polynomial of degree d over the base field, returns P(x). The function cmul(E,P,a,y) must return the coefficient of degree a of P multiplied by y. cmul is allowed to return a non canonical form; it is also allowed to return NULL instead of an exact 0.

The flag use_sqr has the same meaning as for gen_powers. This implements an algorithm of Brent and Kung (1978).

GEN gen_bkeval_powers(GEN P, long d, GEN V, void *E, const struct bb_algebra *ff, GEN cmul(void *E, GEN P, long a, GEN x)) as gen_RgX_bkeval assuming V was output by gen_powers(x, l, E, ff) for some l >= 1. For optimal performance, l should be computed by brent_kung_optpow.

long brent_kung_optpow(long d, long n, long m) returns the optimal parameter l for the evaluation of n/m polynomials of degree d. Fractional values can be used if the evaluations are done with different accuracies, and thus have different weights.

## Functions returning black box algebras

const struct bb_algebra * get_FpX_algebra(void **E, GEN p, long v) return the algebra of polynomials over F_p in variable v.

const struct bb_algebra * get_FpXQ_algebra(void **E, GEN T, GEN p) return the algebra F_p[X]/(T(X)).

const struct bb_algebra * get_FpXQX_algebra(void **E, GEN T, GEN p, long v) return the algebra of polynomials over F_p[X]/(T(X)) in variable v.

const struct bb_algebra * get_FlxqXQ_algebra(void **E, GEN S, GEN T, ulong p) return the algebra F_p[X,Y]/(S(X,Y),T(X)) (for ulong p).

const struct bb_algebra * get_FpXQXQ_algebra(void **E, GEN S, GEN T, GEN p) return the algebra F_p[X,Y]/(S(X,Y),T(X)).

const struct bb_algebra * get_Rg_algebra(void) return the generic algebra.

# Black box ring

A black box ring is defined by a bb_ring struct, describing methods available to handle ring elements:

  struct bb_ring
{
GEN (*add)(void *E, GEN x, GEN y);
GEN (*mul)(void *E, GEN x, GEN y);
GEN (*sqr)(void *E, GEN x);
};

add(E,x,y) returns the sum x+y.

mul(E,x,y) returns the product x y.

sqr(E,x) returns the square x^2.

GEN gen_fromdigits(GEN v, GEN B, void *E, struct bb_ring *r) where B is a ring element and v = [c_0,...,c_{n-1}] a vector of ring elements, return sum_{i = 0}^n c_i B^i using binary splitting.

GEN gen_digits(GEN x, GEN B, long n, void *E, struct bb_ring *r, GEN (*div)(void *E, GEN x, GEN y, GEN *r))

(Require the ring to be Euclidean)

div(E,x,y,&r) performs the Euclidean division of x by y in the ring R, returning the quotient q and setting r to the residue so that x = q y+r holds. The residue must belong to a fixed set of representatives of R/(y).

The argument x being a ring element, gen_digits returns a vector of ring elements [c_0,...,c_{n-1}] such that x = sum_{i = 0}^n c_i B^i. Furthermore for all i != n-1, the elements c_i belonging to the fixed set of representatives of R/(B).

# Black box free Z_p-modules

(Very experimental)

GEN gen_ZpX_Dixon(GEN F, GEN V, GEN q, GEN p, long N, void *E, GEN lin(void *E, GEN F, GEN z, GEN q), GEN invl(void *E, GEN z))

Let F be a ZpXT representing the coefficients of some abstract linear mapping f over Z_p[X] seen as a free Z_p-module, let V be an element of Z_p[X] and let q = p^N. Return y\inZ_p[X] such that f(y) = V (mod p^N) assuming the following holds for n <= N:

@3* lin(E, FpX_red(F, p^n), z, p^n) = f(z) (mod p^n)

@3* f(invl(E, z)) = z (mod p)

The rationale for the argument F being that it allows gen_ZpX_Dixon to reduce it to the required p-adic precision.

GEN gen_ZpX_Newton(GEN x, GEN p, long n, void *E, GEN eval(void *E, GEN a, GEN q), GEN invd(void *E, GEN b, GEN v, GEN q, long N))

Let x be an element of Z_p[X] seen as a free Z_p-module, and f some differentiable function over Z_p[X] such that f(x) = 0 (mod p). Return y such that f(y) = 0 (mod p^n), assuming the following holds for all a, b\in Z_p[X] and M <= N:

@3* v = eval(E,a,p^N) is a vector of elements of Z_p[X],

@3* w = invd(E,b,v,p^M,M) is an element in Z_p[X],

@3* v[1] = f(a) (mod p^NZ_p[X]),

@3* df_a(w) = b (mod p^MZ_p[X])

@3and df_a denotes the differential of f at a. Motivation: eval allows to evaluate f and invd allows to invert its differential. Frequently, data useful to compute the differential appear as a subproduct of computing the function. The vector v allows eval to provide these to invd. The implementation of invd will generally involves the use of the function gen_ZpX_Dixon.

\newpage

# NAME

libPARI - Operations on general PARI objects

# Assignment

It is in general easier to use a direct conversion, e.g. y = stoi(s), than to allocate a target of correct type and sufficient size, then assign to it:

    GEN y = cgeti(3); affsi(s, y);

These functions can still be moderately useful in complicated garbage collecting scenarios but you will be better off not using them.

void gaffsg(long s, GEN x) assigns the long s into the object x.

void gaffect(GEN x, GEN y) assigns the object x into the object y. Both x and y must be scalar types. Type conversions (e.g. from t_INT to t_REAL or t_INTMOD) occur if legitimate.

int is_universal_constant(GEN x) returns 1 if x is a global PARI constant you should never assign to (such as gen_1), and 0 otherwise.

# Conversions

## Scalars

double rtodbl(GEN x) applied to a t_REAL x, converts x into a double if possible.

GEN dbltor(double x) converts the double x into a t_REAL.

long dblexpo(double x) returns expo(dbltor(x)), but faster and without cluttering the stack.

ulong dblmantissa(double x) returns the most significant word in the mantissa of dbltor(x).

double gtodouble(GEN x) if x is a real number (not necessarily a t_REAL), converts x into a double if possible.

long gtos(GEN x) converts the t_INT x to a small integer if possible, otherwise raise an exception. This function is similar to itos, slightly slower since it checks the type of x.

double dbllog2r(GEN x) assuming that x is a non-zero t_REAL, returns an approximation to log2(|x|).

double dblmodulus(GEN x) return an approximation to |x|.

long gtolong(GEN x) if x is an integer (not necessarily a t_INT), converts x into a long if possible.

GEN fractor(GEN x, long l) applied to a t_FRAC x, converts x into a t_REAL of length prec.

GEN quadtofp(GEN x, long l) applied to a t_QUAD x, converts x into a t_REAL or t_COMPLEX depending on the sign of the discriminant of x, to precision l BIL-bit words.

GEN cxtofp(GEN x, long prec) converts the t_COMPLEX x to a a complex whose real and imaginary parts are t_REAL of length prec (special case of gtofp.

GEN cxcompotor(GEN x, long prec) converts the t_INT, t_REAL or t_FRAC x to a t_REAL of length prec. These are all the real types which may occur as components of a t_COMPLEX; special case of gtofp (introduced so that the latter is not recursive and can thus be inlined).

GEN gtofp(GEN x, long prec) converts the complex number x (t_INT, t_REAL, t_FRAC, t_QUAD or t_COMPLEX) to either a t_REAL or t_COMPLEX whose components are t_REAL of precision prec; not necessarily of length prec: a real 0 may be given as real_0(...)). If the result is a t_COMPLEX extra care is taken so that its modulus really has accuracy prec: there is a problem if the real part of the input is an exact 0; indeed, converting it to real_0(prec) would be wrong if the imaginary part is tiny, since the modulus would then become equal to 0, as in 1.E-100 + 0.E-28 = 0.E-28.

GEN gtomp(GEN z, long prec) converts the real number x (t_INT, t_REAL, t_FRAC, real t_QUAD) to either a t_INT or a t_REAL of precision prec. Not memory clean if x is a t_INT: we return x itself and not a copy.

GEN gcvtop(GEN x, GEN p, long l) converts x into a t_PADIC of precision l. Works componentwise on recursive objects, e.g. t_POL or t_VEC. Converting 0 yields O(p^l); converting a non-zero number yield a result well defined modulo p^{v_p(x) + l}.

GEN cvtop(GEN x, GEN p, long l) as gcvtop, assuming that x is a scalar.

GEN cvtop2(GEN x, GEN y) y being a p-adic, converts the scalar x to a p-adic of the same accuracy. Shallow function.

GEN cvstop2(long s, GEN y) y being a p-adic, converts the scalar s to a p-adic of the same accuracy. Shallow function.

GEN gprec(GEN x, long l) returns a copy of x whose precision is changed to l digits. The precision change is done recursively on all components of x. Digits means decimal, p-adic and X-adic digits for t_REAL, t_SER, t_PADIC components, respectively.

GEN gprec_w(GEN x, long l) returns a shallow copy of x whose t_REAL components have their precision changed to l words. This is often more useful than gprec.

GEN gprec_wtrunc(GEN x, long l) returns a shallow copy of x whose t_REAL components have their precision truncated to l words. Contrary to gprec_w, this function may never increase the precision of x.

## Modular objects / lifts

GEN gmodulo(GEN x, GEN y) creates the object Mod(x,y) on the PARI stack, where x and y are either both t_INTs, and the result is a t_INTMOD, or x is a scalar or a t_POL and y a t_POL, and the result is a t_POLMOD.

GEN gmodulgs(GEN x, long y) same as gmodulo except y is a long.

GEN gmodulsg(long x, GEN y) same as gmodulo except x is a long.

GEN gmodulss(long x, long y) same as gmodulo except both x and y are longs.

GEN lift_shallow(GEN x) shallow version of lift

GEN liftall_shallow(GEN x) shallow version of liftall

GEN liftint_shallow(GEN x) shallow version of liftint

GEN liftpol_shallow(GEN x) shallow version of liftpol

GEN centerlift0(GEN x,long v) DEPRECATED, kept for backward compatibility only: use either lift0(x,v) or centerlift(x).

## Between polynomials and coefficient arrays

GEN gtopoly(GEN x, long v) converts or truncates the object x into a t_POL with main variable number v. A common application would be the conversion of coefficient vectors (coefficients are given by decreasing degree). E.g. [2,3] goes to 2*v + 3

GEN gtopolyrev(GEN x, long v) converts or truncates the object x into a t_POL with main variable number v, but vectors are converted in reverse order compared to gtopoly (coefficients are given by increasing degree). E.g. [2,3] goes to 3*v + 2. In other words the vector represents a polynomial in the basis (1,v,v^2,v^3,...).

GEN normalizepol(GEN x) applied to an unnormalized t_POL x (with all coefficients correctly set except that leading_term(x) might be zero), normalizes x correctly in place and returns x. For internal use. Normalizing means deleting all leading exact zeroes (as per isexactzero), except if the polynomial turns out to be 0, in which case we try to find a coefficient c which is a non-rational zero, and return the constant polynomial c. (We do this so that information about the base ring is not lost.)

GEN normalizepol_lg(GEN x, long l) applies normalizepol to x, pretending that lg(x) is l, which must be less than or equal to lg(x). If equal, the function is equivalent to normalizepol(x).

GEN normalizepol_approx(GEN x, long lx) as normalizepol_lg, with the difference that we just delete all leading zeroes (as per gequal0). This rougher normalization is used when we have no other choice, for instance before attempting a Euclidean division by x.

The following routines do not copy coefficients on the stack (they only move pointers around), hence are very fast but not suitable for gerepile calls. Recall that an RgV (resp. an RgX, resp. an RgM) is a t_VEC or t_COL (resp. a t_POL, resp. a t_MAT) with arbitrary components. Similarly, an RgXV is a t_VEC or t_COL with RgX components, etc.

GEN RgV_to_RgX(GEN x, long v) converts the RgV x to a (normalized) polynomial in variable v (as gtopolyrev, without copy).

GEN RgV_to_RgX_reverse(GEN x, long v) converts the RgV x to a (normalized) polynomial in variable v (as gtopoly, without copy).

GEN RgX_to_RgC(GEN x, long N) converts the t_POL x to a t_COL v with N components. Coefficients of x are listed by increasing degree, so that y[i] is the coefficient of the term of degree i-1 in x.

GEN Rg_to_RgC(GEN x, long N) as RgX_to_RgV, except that other types than t_POL are allowed for x, which is then considered as a constant polynomial.

GEN RgM_to_RgXV(GEN x, long v) converts the RgM x to a t_VEC of RgX, by repeated calls to RgV_to_RgX.

GEN RgV_to_RgM(GEN v, long N) converts the vector v to a t_MAT with N rows, by repeated calls to Rg_to_RgV.

GEN RgXV_to_RgM(GEN v, long N) converts the vector of RgX v to a t_MAT with N rows, by repeated calls to RgX_to_RgV.

GEN RgM_to_RgXX(GEN x, long v,long w) converts the RgM x into a t_POL in variable v, whose coefficients are t_POLs in variable w. This is a shortcut for

    RgV_to_RgX( RgM_to_RgXV(x, w), v );

There are no consistency checks with respect to variable priorities: the above is an invalid object if varncmp(v, w) >= 0.

GEN RgXX_to_RgM(GEN x, long N) converts the t_POL x with RgX (or constant) coefficients to a matrix with N rows.

long RgXY_degreex(GEN P) return the degree of P with respect to the secondary variable.

GEN RgXY_swap(GEN P, long n, long w) converts the bivariate polynomial P(u,v) (a t_POL with t_POL or scalar coefficients) to P(pol_x[w],u), assuming n is an upper bound for deg _v(P).

GEN RgXY_swapspec(GEN C, long n, long w, long lP) as RgXY_swap where the coefficients of P are given by gel(C,0),...,gel(C,lP-1).

GEN RgX_to_ser(GEN x, long l) applied to a t_POL x, creates a shallow t_SER of length l >= 2 starting with x. Unless the polynomial is an exact zero, the coefficient of lowest degree T^d of the result is not an exact zero (as per isexactzero). The remainder is O(T^{d+l}).

GEN RgX_to_ser_inexact(GEN x, long l) applied to a t_POL x, creates a shallow t_SER of length l starting with x. Unless the polynomial is zero, the coefficient of lowest degree T^d of the result is not zero (as per gequal0). The remainder is O(T^{d+l}).

GEN rfrac_to_ser(GEN x, long l) applied to a t_RFRAC x, creates a t_SER of length l congruent to x. Not memory-clean but suitable for gerepileupto.

GEN gtoser(GEN s, long v, long d) converts the object s into a t_SER with main variable number v and d > 0 significant terms. More precisely

@3* if s is a scalar, we return a constant power series with d significant terms.

@3* if s is a t_POL, it is truncated to d terms if needed.

@3* If s is a vector, the coefficients of the vector are understood to be the coefficients of the power series starting from the constant term (as in Polrev), and the precision d is ignored.

@3* If s is already a power series in v, we retur a copy, and the precision d is again ignored.

GEN gtocol(GEN x) converts the object x into a t_COL

GEN gtomat(GEN x) converts the object x into a t_MAT.

GEN gtovec(GEN x) converts the object x into a t_VEC.

GEN gtovecsmall(GEN x) converts the object x into a t_VECSMALL.

GEN normalize(GEN x) applied to an unnormalized t_SER x (i.e. type t_SER with all coefficients correctly set except that x[2] might be zero), normalizes x correctly in place. Returns x. For internal use.

GEN serchop0(GEN s) given a t_SER of the form x^v s(x), with s(0) != 0, return x^v(s - s(0)). Shallow function.

# Constructors

## Clean constructors

GEN zeropadic(GEN p, long n) creates a 0 t_PADIC equal to O(p^n).

GEN zeroser(long v, long n) creates a 0 t_SER in variable v equal to O(X^n).

GEN scalarser(GEN x, long v, long prec) creates a constant t_SER in variable v and precision prec, whose constant coefficient is (a copy of) x, in other words x + O(v^prec). Assumes that prec >= 0.

GEN pol_0(long v) Returns the constant polynomial 0 in variable v.

GEN pol_1(long v) Returns the constant polynomial 1 in variable v.

GEN pol_x(long v) Returns the monomial of degree 1 in variable v.

GEN pol_xn(long n, long v) Returns the monomial of degree n in variable v; assume that n >= 0.

GEN pol_xnall(long n, long v) Returns the Laurent monomial of degree n in variable v; n < 0 is allowed.

GEN pol_x_powers(long N, long v) returns the powers of pol_x(v), of degree 0 to N-1, in a vector with N components.

GEN scalarpol(GEN x, long v) creates a constant t_POL in variable v, whose constant coefficient is (a copy of) x.

GEN deg1pol(GEN a, GEN b,long v) creates the degree 1 t_POL a pol_x(v) + b

GEN zeropol(long v) is identical pol_0.

GEN zerocol(long n) creates a t_COL with n components set to gen_0.

GEN zerovec(long n) creates a t_VEC with n components set to gen_0.

GEN col_ei(long n, long i) creates a t_COL with n components set to gen_0, but for the i-th one which is set to gen_1 (i-th vector in the canonical basis).

GEN vec_ei(long n, long i) creates a t_VEC with n components set to gen_0, but for the i-th one which is set to gen_1 (i-th vector in the canonical basis).

GEN trivial_fact(void) returns the trivial (empty) factorization Mat([]~,[]~)

GEN prime_fact(GEN x) returns the factorization Mat([x]~, [1]~)

GEN Rg_col_ei(GEN x, long n, long i) creates a t_COL with n components set to gen_0, but for the i-th one which is set to x.

GEN vecsmall_ei(long n, long i) creates a t_VECSMALL with n components set to 0, but for the i-th one which is set to 1 (i-th vector in the canonical basis).

GEN scalarcol(GEN x, long n) creates a t_COL with n components set to gen_0, but the first one which is set to a copy of x. (The name comes from RgV_isscalar.)

GEN mkintmodu(ulong x, ulong y) creates the t_INTMOD Mod(x, y). The inputs must satisfy x < y.

GEN zeromat(long m, long n) creates a t_MAT with m x n components set to gen_0. Note that the result allocates a single column, so modifying an entry in one column modifies it in all columns. To fully allocate a matrix initialized with zero entries, use zeromatcopy.

GEN zeromatcopy(long m, long n) creates a t_MAT with m x n components set to gen_0.

GEN matid(long n) identity matrix in dimension n (with components gen_1 andgen_0).

GEN scalarmat(GEN x, long n) scalar matrix, x times the identity.

GEN scalarmat_s(long x, long n) scalar matrix, stoi(x) times the identity.

GEN vecrange(GEN a, GEN b) returns the t_VEC [a..b].

GEN vecrangess(long a, long b) returns the t_VEC [a..b].

GEN mkfraccopy(GEN x, GEN y) creates the t_FRAC x/y. Assumes that y > 1 and (x,y) = 1.

GEN mkrfraccopy(GEN x, GEN y) creates the t_RFRAC x/y. Assumes that y is a t_POL, x a compatible type whose variable has lower or same priority, with (x,y) = 1.

GEN mkcolcopy(GEN x) creates a 1-dimensional t_COL containing x.

GEN mkmatcopy(GEN x) creates a 1-by-1 t_MAT wrapping the t_COL x.

GEN mkveccopy(GEN x) creates a 1-dimensional t_VEC containing x.

GEN mkvec2copy(GEN x, GEN y) creates a 2-dimensional t_VEC equal to [x,y].

GEN mkcols(long x) creates a 1-dimensional t_COL containing stoi(x).

GEN mkcol2s(long x, long y) creates a 2-dimensional t_COL containing [stoi(x), stoi(y)] .

GEN mkcol3s(long x, long y, long z) creates a 3-dimensional t_COL containing [stoi(x), stoi(y), stoi(z)] .

GEN mkcol4s(long x, long y, long z, long t) creates a 4-dimensional t_COL containing [stoi(x), stoi(y), stoi(z), stoi(t)] .

GEN mkvecs(long x) creates a 1-dimensional t_VEC containing stoi(x).

GEN mkvec2s(long x, long y) creates a 2-dimensional t_VEC containing [stoi(x), stoi(y)].

GEN mkvec3s(long x, long y, long z) creates a 3-dimensional t_VEC containing [stoi(x), stoi(y), stoi(z)].

GEN mkvec4s(long x, long y, long z, long t) creates a 4-dimensional t_VEC containing [stoi(x), stoi(y), stoi(z), stoi(t)].

GEN mkvecsmall(long x) creates a 1-dimensional t_VECSMALL containing x.

GEN mkvecsmall2(long x, long y) creates a 2-dimensional t_VECSMALL containing [x, y].

GEN mkvecsmall3(long x, long y, long z) creates a 3-dimensional t_VECSMALL containing [x, y, z].

GEN mkvecsmall4(long x, long y, long z, long t) creates a 4-dimensional t_VECSMALL containing [x, y, z, t].

GEN mkvecsmalln(long n, ...) returns the t_VECSMALL whose n coefficients (long) follow. Warning: since this is a variadic function, C type promotion is not performed on the arguments by the compiler, thus you have to make sure that all the arguments are of type long, in particular integer constants need to be written with the L suffix: mkvecsmalln(2, 1L, 2L) is correct, but mkvecsmalln(2, 1, 2) is not.

## Unclean constructors

Contrary to the policy of general PARI functions, the functions in this subsection do not copy their arguments, nor do they produce an object a priori suitable for gerepileupto. In particular, they are faster than their clean equivalent (which may not exist). If you restrict their arguments to universal objects (e.g gen_0), then the above warning does not apply.

GEN mkcomplex(GEN x, GEN y) creates the t_COMPLEX x + iy.

GEN mulcxI(GEN x) creates the t_COMPLEX ix. The result in general contains data pointing back to the original x. Use gcopy if this is a problem. But in most cases, the result is to be used immediately, before x is subject to garbage collection.

GEN mulcxmI(GEN x), as mulcxI, but returns the t_COMPLEX -ix.

GEN mkquad(GEN n, GEN x, GEN y) creates the t_QUAD x + yw, where w is a root of n, which is of the form quadpoly(D).

GEN mkfrac(GEN x, GEN y) creates the t_FRAC x/y. Assumes that y > 1 and (x,y) = 1.

GEN mkrfrac(GEN x, GEN y) creates the t_RFRAC x/y. Assumes that y is a t_POL, x a compatible type whose variable has lower or same priority, with (x,y) = 1.

GEN mkcol(GEN x) creates a 1-dimensional t_COL containing x.

GEN mkcol2(GEN x, GEN y) creates a 2-dimensional t_COL equal to [x,y].

GEN mkcol3(GEN x, GEN y, GEN z) creates a 3-dimensional t_COL equal to [x,y,z].

GEN mkcol4(GEN x, GEN y, GEN z, GEN t) creates a 4-dimensional t_COL equal to [x,y,z,t].

GEN mkcol5(GEN a1, GEN a2, GEN a3, GEN a4, GEN a5) creates the 5-dimensional t_COL equal to [a_1,a_2,a_3,a_4,a_5].

GEN mkcol6(GEN x, GEN y, GEN z, GEN t, GEN u, GEN v) creates the 6-dimensional column vector [x,y,z,t,u,v] .

GEN mkintmod(GEN x, GEN y) creates the t_INTMOD Mod(x, y). The inputs must be t_INTs satisfying 0 <= x < y.

GEN mkpolmod(GEN x, GEN y) creates the t_POLMOD Mod(x, y). The input must satisfy deg  x <  deg  y with respect to the main variable of the t_POL y. x may be a scalar.

GEN mkmat(GEN x) creates a 1-column t_MAT with column x (a t_COL).

GEN mkmat2(GEN x, GEN y) creates a 2-column t_MAT with columns x, y (t_COLs of the same length).

GEN mkmat3(GEN x, GEN y, GEN z) creates a 3-column t_MAT with columns x, y, z (t_COLs of the same length).

GEN mkmat4(GEN x, GEN y, GEN z, GEN t) creates a 4-column t_MAT with columns x, y, z, t (t_COLs of the same length).

GEN mkmat5(GEN x, GEN y, GEN z, GEN t, GEN u) creates a 5-column t_MAT with columns x, y, z, t, u (t_COLs of the same length).

GEN mkvec(GEN x) creates a 1-dimensional t_VEC containing x.

GEN mkvec2(GEN x, GEN y) creates a 2-dimensional t_VEC equal to [x,y].

GEN mkvec3(GEN x, GEN y, GEN z) creates a 3-dimensional t_VEC equal to [x,y,z].

GEN mkvec4(GEN x, GEN y, GEN z, GEN t) creates a 4-dimensional t_VEC equal to [x,y,z,t].

GEN mkvec5(GEN a1, GEN a2, GEN a3, GEN a4, GEN a5) creates the 5-dimensional t_VEC equal to [a_1,a_2,a_3,a_4,a_5].

GEN mkqfi(GEN x, GEN y, GEN z) creates t_QFI equal to Qfb(x,y,z), assuming that y^2 - 4xz < 0.

GEN mkerr(long n) returns a t_ERROR with error code n (enum err_list).

It is sometimes useful to return such a container whose entries are not universal objects, but nonetheless suitable for gerepileupto. If the entries can be computed at the time the result is returned, the following macros achieve this effect:

GEN retmkvec(GEN x) returns a vector containing the single entry x, where the vector root is created just before the function argument x is evaluated. Expands to

    {
GEN res = cgetg(2, t_VEC);
gel(res, 1) = x; /*  or rather, the I<expansion> of x */
return res;
}

@3For instance, the retmkvec(gcopy(x)) returns a clean object, just like return mkveccopy(x) would.

GEN retmkvec2(GEN x, GEN y) returns the 2-dimensional t_VEC [x,y].

GEN retmkvec3(GEN x, GEN y, GEN z) returns the 3-dimensional t_VEC [x,y,z].

GEN retmkvec4(GEN x, GEN y, GEN z, GEN t) returns the 4-dimensional t_VEC [x,y,z,t].

GEN retmkvec5(GEN x, GEN y, GEN z, GEN t, GEN u) returns the 5-dimensional row vector [x,y,z,t,u].

GEN retconst_vec(long n, GEN x) returns the n-dimensional t_VEC whose entries are constant and all equal to x.

GEN retmkcol(GEN x) returns the 1-dimensional t_COL [x] .

GEN retmkcol2(GEN x, GEN y) returns the 2-dimensional t_COL [x,y] .

GEN retmkcol3(GEN x, GEN y, GEN z) returns the 3-dimensional t_COL [x,y,z] .

GEN retmkcol4(GEN x, GEN y, GEN z, GEN t) returns the 4-dimensional t_COL [x,y,z,t] .

GEN retmkcol5(GEN x, GEN y, GEN z, GEN t, GEN u) returns the 5-dimensional column vector [x,y,z,t,u] .

GEN retmkcol6(GEN x, GEN y, GEN z, GEN t, GEN u, GEN v) returns the 6-dimensional column vector [x,y,z,t,u,v] .

GEN retconst_col(long n, GEN x) returns the n-dimensional t_COL whose entries are constant and all equal to x.

GEN retmkmat(GEN x) returns the 1-column t_MAT with colum x.

GEN retmkmat2(GEN x, GEN y) returns the 2-column t_MAT with columns x, y.

GEN retmkmat3(GEN x, GEN y, GEN z) returns the 3-dimensional t_MAT with columns x, y, z.

GEN retmkmat4(GEN x, GEN y, GEN z, GEN t) returns the 4-dimensional t_MAT with columns x, y, z, t.

GEN retmkmat5(GEN x, GEN y, GEN z, GEN t, GEN u) returns the 5-dimensional t_MAT with columns x, y, z, t, u.

GEN retmkcomplex(GEN x, GEN y) returns the t_COMPLEX x + I*y.

GEN retmkfrac(GEN x, GEN y) returns the t_FRAC x / y. Assume x and y are coprime and y > 1.

GEN retmkrfrac(GEN x, GEN y) returns the t_RFRAC x / y. Assume x and y are coprime and more generally that the rational function cannot be simplified.

GEN retmkintmod(GEN x, GEN y) returns the t_INTMOD Mod(x, y).

GEN retmkqfi(GEN a, GEN b, GEN c).

GEN retmkqfr(GEN a, GEN b, GEN c, GEN d).

GEN retmkquad(GEN n, GEN a, GEN b).

GEN retmkpolmod(GEN x, GEN y) returns the t_POLMOD Mod(x, y).

GEN mkintn(long n, ...) returns the non-negative t_INT whose development in base 2^{32} is given by the following n 32bit-words (unsigned int).

    mkintn(3, a2, a1, a0);

@3returns a_2 2^{64} + a_1 2^{32} + a_0.

GEN mkpoln(long n, ...) Returns the t_POL whose n coefficients (GEN) follow, in order of decreasing degree.

    mkpoln(3, gen_1, gen_2, gen_0);

@3returns the polynomial X^2 + 2X (in variable 0, use setvarn if you want other variable numbers). Beware that n is the number of coefficients, hence one more than the degree.

GEN mkvecn(long n, ...) returns the t_VEC whose n coefficients (GEN) follow.

GEN mkcoln(long n, ...) returns the t_COL whose n coefficients (GEN) follow.

GEN scalarcol_shallow(GEN x, long n) creates a t_COL with n components set to gen_0, but the first one which is set to a shallow copy of x. (The name comes from RgV_isscalar.)

GEN scalarmat_shallow(GEN x, long n) creates an n x n scalar matrix whose diagonal is set to shallow copies of the scalar x.

GEN diagonal_shallow(GEN x) returns a diagonal matrix whose diagonal is given by the vector x. Shallow function.

GEN scalarpol_shallow(GEN a, long v) returns the degree 0 t_POL a pol_x(v)^0.

GEN deg1pol_shallow(GEN a, GEN b,long v) returns the degree 1 t_POL apol_x(v) + b

GEN zeropadic_shallow(GEN p, long n) returns a (shallow) 0 t_PADIC equal to O(p^n).

## From roots to polynomials

GEN deg1_from_roots(GEN L, long v) given a vector L of scalars, returns the vector of monic linear polynomials in variable v whose roots are the L[i], i.e. the x - L[i].

GEN roots_from_deg1(GEN L) given a vector L of monic linear polynomials, return their roots, i.e. the - L[i](0).

GEN roots_to_pol(GEN L, long v) given a vector of scalars L, returns the monic polynomial in variable v whose roots are the L[i]. Leaves some garbage on stack, but suitable for gerepileupto.

GEN roots_to_pol_r1(GEN L, long v, long r1) as roots_to_pol assuming the first r_1 roots are real'', and the following ones are representatives of conjugate pairs of complex'' roots. So if L has r_1 + r_2 elements, we obtain a polynomial of degree r_1 + 2r_2. In most applications, the roots are indeed real and complex, but the implementation assumes only that each complex'' root z introduces a quadratic factor X^2 - trace(z) X + norm(z). Leaves some garbage on stack, but suitable for gerepileupto.

# Integer parts

GEN gfloor(GEN x) creates the floor of x, i.e. the (true) integral part.

GEN gfrac(GEN x) creates the fractional part of x, i.e. x minus the floor of x.

GEN gceil(GEN x) creates the ceiling of x.

GEN ground(GEN x) rounds towards + oo  the components of x to the nearest integers.

GEN grndtoi(GEN x, long *e) same as ground, but in addition sets *e to the binary exponent of x - ground(x). If this is positive, all significant bits are lost. This kind of situation raises an error message in ground but not in grndtoi.

GEN gtrunc(GEN x) truncates x. This is the false integer part if x is a real number (i.e. the unique integer closest to x among those between 0 and x). If x is a t_SER, it is truncated to a t_POL; if x is a t_RFRAC, this takes the polynomial part.

GEN gtrunc2n(GEN x, long n) creates the floor of 2^nx, this is only implemented for t_INT, t_REAL, t_FRAC and t_COMPLEX of those.

GEN gcvtoi(GEN x, long *e) analogous to grndtoi for t_REAL inputs except that rounding is replaced by truncation. Also applies componentwise for vector or matrix inputs; otherwise, sets *e to -HIGHEXPOBIT (infinite real accuracy) and return gtrunc(x).

# Valuation and shift

GEN gshift[z](GEN x, long n[, GEN z]) yields the result of shifting (the components of) x left by n (if n is non-negative) or right by -n (if n is negative). Applies only to t_INT and vectors/matrices of such. For other types, it is simply multiplication by 2^{n}.

GEN gmul2n[z](GEN x, long n[, GEN z]) yields the product of x and 2^{n}. This is different from gshift when n is negative and x is a t_INT: gshift truncates, while gmul2n creates a fraction if necessary.

long gvaluation(GEN x, GEN p) returns the greatest exponent e such that p^e divides x, when this makes sense.

long gval(GEN x, long v) returns the highest power of the variable number v dividing the t_POL x.

# Comparison operators

## Generic

long gcmp(GEN x, GEN y) comparison of x with y: returns 1 (x > y), 0 (x = y) or -1 (x < y). Two t_STR are compared using the standard lexicographic ordering; a t_STR is considered strictly larger than any non-string type. If neither x nor y is a t_STR, their allowed types are t_INT, t_REAL or t_FRAC. Used cmp_universal to compare arbitrary GENs.

long lexcmp(GEN x, GEN y) comparison of x with y for the lexicographic ordering; when comparing objects of different lengths whose components are all equal up to the smallest of their length, consider that the longest is largest. Consider scalars as 1-component vectors. Return gcmp(x,y) if both arguments are scalars.

int gequalX(GEN x) return 1 (true) if x is a variable (monomial of degree 1 with t_INT coefficients equal to 1 and 0), and 0 otherwise

long gequal(GEN x, GEN y) returns 1 (true) if x is equal to y, 0 otherwise. A priori, this makes sense only if x and y have the same type, in which case they are recursively compared componentwise. When the types are different, a true result means that x - y was successfully computed and that gequal0 found it equal to 0. In particular

    gequal(cgetg(1, t_VEC), gen_0)

@3is true, and the relation is not transitive. E.g. an empty t_COL and an empty t_VEC are not equal but are both equal to gen_0.

long gidentical(GEN x, GEN y) returns 1 (true) if x is identical to y, 0 otherwise. In particular, the types and length of x and y must be equal. This test is much stricter than gequal, in particular, t_REAL with different accuracies are tested different. This relation is transitive.

## Comparison with a small integer

int isexactzero(GEN x) returns 1 (true) if x is exactly equal to 0 (including t_INTMODs like Mod(0,2)), and 0 (false) otherwise. This includes recursive objects, for instance vectors, whose components are 0.

GEN gisexactzero(GEN x) returns NULL unless x is exactly equal to 0 (as per isexactzero). When x is an exact zero return the attached scalar zero as a t_INT (gen_0), a t_INTMOD (Mod(0,N) for the largest possible N) or a t_FFELT.

int isrationalzero(GEN x) returns 1 (true) if x is equal to an integer 0 (excluding t_INTMODs like Mod(0,2)), and 0 (false) otherwise. Contrary to isintzero, this includes recursive objects, for instance vectors, whose components are 0.

int ismpzero(GEN x) returns 1 (true) if x is a t_INT or a t_REAL equal to 0.

int isintzero(GEN x) returns 1 (true) if x is a t_INT equal to 0.

int isint1(GEN x) returns 1 (true) if x is a t_INT equal to 1.

int isintm1(GEN x) returns 1 (true) if x is a t_INT equal to -1.

int equali1(GEN n) Assuming that x is a t_INT, return 1 (true) if x is equal to 1, and return 0 (false) otherwise.

int equalim1(GEN n) Assuming that x is a t_INT, return 1 (true) if x is equal to -1, and return 0 (false) otherwise.

int is_pm1(GEN x). Assuming that x is a non-zero t_INT, return 1 (true) if x is equal to -1 or 1, and return 0 (false) otherwise.

int gequal0(GEN x) returns 1 (true) if x is equal to 0, 0 (false) otherwise.

int gequal1(GEN x) returns 1 (true) if x is equal to 1, 0 (false) otherwise.

int gequalm1(GEN x) returns 1 (true) if x is equal to -1, 0 (false) otherwise.

long gcmpsg(long s, GEN x)

long gcmpgs(GEN x, long s) comparison of x with the long s.

GEN gmaxsg(long s, GEN x)

GEN gmaxgs(GEN x, long s) returns the largest of x and the long s (converted to GEN)

GEN gminsg(long s, GEN x)

GEN gmings(GEN x, long s) returns the smallest of x and the long s (converted to GEN)

long gequalsg(long s, GEN x)

long gequalgs(GEN x, long s) returns 1 (true) if x is equal to the long s, 0 otherwise.

# Miscellaneous Boolean functions

int isrationalzeroscalar(GEN x) equivalent to, but faster than,

    is_scalar_t(typ(x)) && isrationalzero(x)

int isinexact(GEN x) returns 1 (true) if x has an inexact component, and 0 (false) otherwise.

int isinexactreal(GEN x) return 1 if x has an inexact t_REAL component, and 0 otherwise.

int isrealappr(GEN x, long e) applies (recursively) to complex inputs; returns 1 if x is approximately real to the bit accuracy e, and 0 otherwise. This means that any t_COMPLEX component must have imaginary part t satisfying gexpo(t) < e.

int isint(GEN x, GEN *n) returns 0 (false) if x does not round to an integer. Otherwise, returns 1 (true) and set n to the rounded value.

int issmall(GEN x, long *n) returns 0 (false) if x does not round to a small integer (suitable for itos). Otherwise, returns 1 (true) and set n to the rounded value.

long iscomplex(GEN x) returns 1 (true) if x is a complex number (of component types embeddable into the reals) but is not itself real, 0 if x is a real (not necessarily of type t_REAL), or raises an error if x is not embeddable into the complex numbers.

## Obsolete

The following less convenient comparison functions and Boolean operators were used by the historical GP interpreter. They are provided for backward compatibility only and should not be used:

GEN gle(GEN x, GEN y)

GEN glt(GEN x, GEN y)

GEN gge(GEN x, GEN y)

GEN ggt(GEN x, GEN y)

GEN geq(GEN x, GEN y)

GEN gne(GEN x, GEN y)

GEN gor(GEN x, GEN y)

GEN gand(GEN x, GEN y)

GEN gnot(GEN x, GEN y)

# Sorting

## Basic sort

GEN sort(GEN x) sorts the vector x in ascending order using a mergesort algorithm, and gcmp as the underlying comparison routine (returns the sorted vector). This routine copies all components of x, use gen_sort_inplace for a more memory-efficient function.

GEN lexsort(GEN x), as sort, using lexcmp instead of gcmp as the underlying comparison routine.

GEN vecsort(GEN x, GEN k), as sort, but sorts the vector x in ascending lexicographic order, according to the entries of the t_VECSMALL k. For example, if k = [2,1,3], sorting will be done with respect to the second component, and when these are equal, with respect to the first, and when these are equal, with respect to the third.

## Indirect sorting

GEN indexsort(GEN x) as sort, but only returns the permutation which, applied to x, would sort the vector. The result is a t_VECSMALL.

GEN indexlexsort(GEN x), as indexsort, using lexcmp instead of gcmp as the underlying comparison routine.

GEN indexvecsort(GEN x, GEN k), as vecsort, but only returns the permutation that would sort the vector x.

long vecindexmin(GEN x) returns the index for a maximal element of x (t_VEC, t_COL or t_VECSMALL).

long vecindexmax(GEN x) returns the index for a maximal element of x (t_VEC, t_COL or t_VECSMALL).

long vecindexmax(GEN x)

The following routines allow to use an arbitrary comparison function int (*cmp)(void* data, GEN x, GEN y), such that cmp(data,x,y) returns a negative result if x < y, a positive one if x > y and 0 if x = y. The data argument is there in case your cmp requires additional context.

GEN gen_sort(GEN x, void *data, int (*cmp)(void *,GEN,GEN)), as sort, with an explicit comparison routine.

GEN gen_sort_uniq(GEN x, void *data, int (*cmp)(void *,GEN,GEN)), as gen_sort, removing duplicate entries.

GEN gen_indexsort(GEN x, void *data, int (*cmp)(void*,GEN,GEN)), as indexsort.

GEN gen_indexsort_uniq(GEN x, void *data, int (*cmp)(void*,GEN,GEN)), as indexsort, removing duplicate entries.

void gen_sort_inplace(GEN x, void *data, int (*cmp)(void*,GEN,GEN), GEN *perm) sort x in place, without copying its components. If perm is non-NULL, it is set to the permutation that would sort the original x.

GEN gen_setminus(GEN A, GEN B, int (*cmp)(GEN,GEN)) given two sorted vectors A and B, returns the vector of elements of A not belonging to B.

GEN sort_factor(GEN y, void *data, int (*cmp)(void *,GEN,GEN)): assuming y is a factorization matrix, sorts its rows in place (no copy is made) according to the comparison function cmp applied to its first column.

GEN merge_sort_uniq(GEN x,GEN y, void *data, int (*cmp)(void *,GEN,GEN)) assuming x and y are sorted vectors, with respect to the cmp comparison function, return a sorted concatenation, with duplicates removed.

GEN merge_factor(GEN fx, GEN fy, void *data, int (*cmp)(void *,GEN,GEN)) let fx and fy be factorization matrices for X and Y sorted with respect to the comparison function cmp (see sort_factor), returns the factorization of X * Y.

long gen_search(GEN v, GEN y, long flag, void *data, int (*cmp)(void*,GEN,GEN)).\hfil

Let v be a vector sorted according to cmp(data,a,b); look for an index i such that v[i] is equal to y. flag has the same meaning as in setsearch: if flag is 0, return i if it exists and 0 otherwise; if flag is non-zero, return 0 if i exists and the index where y should be inserted otherwise.

long tablesearch(GEN T, GEN x, int (*cmp)(GEN,GEN)) is a faster implementation for the common case gen_search(T,x,0,cmp,cmp_nodata).

## Further useful comparison functions

int cmp_universal(GEN x, GEN y) a somewhat arbitrary universal comparison function, devoid of sensible mathematical meaning. It is transitive, and returns 0 if and only if gidentical(x,y) is true. Useful to sort and search vectors of arbitrary data.

int cmp_nodata(void *data, GEN x, GEN y). This function is a hack used to pass an existing basic comparison function lacking the data argument, i.e. with prototype int (*cmp)(GEN x, GEN y). Instead of gen_sort(x, NULL, cmp) which may or may not work depending on how your compiler handles typecasts between incompatible function pointers, one should use gen_sort(x, (void*)cmp, cmp_nodata).

Here are a few basic comparison functions, to be used with cmp_nodata:

int ZV_cmp(GEN x, GEN y) compare two ZV, which we assume have the same length (lexicographic order).

int cmp_Flx(GEN x, GEN y) compare two Flx, which we assume have the same main variable (lexicographic order).

int cmp_RgX(GEN x, GEN y) compare two polynomials, which we assume have the same main variable (lexicographic order). The coefficients are compared using gcmp.

int cmp_prime_over_p(GEN x, GEN y) compare two prime ideals, which we assume divide the same prime number. The comparison is ad hoc but orders according to increasing residue degrees.

int cmp_prime_ideal(GEN x, GEN y) compare two prime ideals in the same nf. Orders by increasing primes, breaking ties using cmp_prime_over_p.

int cmp_padic(GEN x, GEN y) compare two t_PADIC (for the same prime p).

Finally a more elaborate comparison function:

int gen_cmp_RgX(void *data, GEN x, GEN y) compare two polynomials, ordering first by increasing degree, then according to the coefficient comparison function:

    int (*cmp_coeff)(GEN,GEN) = (int(*)(GEN,GEN)) data;

# Divisibility, Euclidean division

GEN gdivexact(GEN x, GEN y) returns the quotient x / y, assuming y divides x. Not stack clean if y = 1 (we return x, not a copy).

int gdvd(GEN x, GEN y) returns 1 (true) if y divides x, 0 otherwise.

GEN gdiventres(GEN x, GEN y) creates a 2-component vertical vector whose components are the true Euclidean quotient and remainder of x and y.

GEN gdivent[z](GEN x, GEN y[, GEN z]) yields the true Euclidean quotient of x and the t_INT or t_POL y, as per the \ GP operator.

GEN gdiventsg(long s, GEN y[, GEN z]), as gdivent except that x is a long.

GEN gdiventgs[z](GEN x, long s[, GEN z]), as gdivent except that y is a long.

GEN gmod[z](GEN x, GEN y[, GEN z]) yields the remainder of x modulo the t_INT or t_POL y, as per the % GP operator. A t_REAL or t_FRAC y is also allowed, in which case the remainder is the unique real r such that 0 <= r < |y| and y = qx + r for some (in fact unique) integer q.

GEN gmodsg(long s, GEN y[, GEN z]) as gmod, except x is a long.

GEN gmodgs(GEN x, long s[, GEN z]) as gmod, except y is a long.

GEN gdivmod(GEN x, GEN y, GEN *r) If r is not equal to NULL or ONLY_REM, creates the (false) Euclidean quotient of x and y, and puts (the address of) the remainder into *r. If r is equal to NULL, do not create the remainder, and if r is equal to ONLY_REM, create and output only the remainder. The remainder is created after the quotient and can be disposed of individually with a cgiv(r).

GEN poldivrem(GEN x, GEN y, GEN *r) same as gdivmod but specifically for t_POLs x and y, not necessarily in the same variable. Either of x and y may also be scalars, treated as polynomials of degree 0.

GEN gdeuc(GEN x, GEN y) creates the Euclidean quotient of the t_POLs x and y. Either of x and y may also be scalars, treated as polynomials of degree 0.

GEN grem(GEN x, GEN y) creates the Euclidean remainder of the t_POL x divided by the t_POL y. Either of x and y may also be scalars, treated as polynomials of degree 0.

GEN gdivround(GEN x, GEN y) if x and y are real (t_INT, t_REAL, t_FRAC), return the rounded Euclidean quotient of x and y as per the \/ GP operator. Operate componentwise if x is a t_COL, t_VEC or t_MAT. Otherwise as gdivent.

GEN centermod_i(GEN x, GEN y, GEN y2), as centermodii, componentwise.

GEN centermod(GEN x, GEN y), as centermod_i, except that y2 is computed (and left on the stack for efficiency).

GEN ginvmod(GEN x, GEN y) creates the inverse of x modulo y when it exists. y must be of type t_INT (in which case x is of type t_INT) or t_POL (in which case x is either a scalar type or a t_POL).

# GCD, content and primitive part

## Generic

GEN resultant(GEN x, GEN y) creates the resultant of the t_POLs x and y computed using Sylvester's matrix (inexact inputs), a modular algorithm (inputs in Q[X]) or the subresultant algorithm, as optimized by Lazard and Ducos. Either of x and y may also be scalars (treated as polynomials of degree 0)

GEN ggcd(GEN x, GEN y) creates the GCD of x and y.

GEN glcm(GEN x, GEN y) creates the LCM of x and y.

GEN gbezout(GEN x,GEN y, GEN *u,GEN *v) returns the GCD of x and y, and puts (the addresses of) objects u and v such that ux+vy =  gcd (x,y) into *u and *v.

GEN subresext(GEN x, GEN y, GEN *U, GEN *V) returns the resultant of x and y, and puts (the addresses of) polynomials u and v such that ux+vy = Res(x,y) into *U and *V.

GEN content(GEN x) returns the GCD of all the components of x.

GEN primitive_part(GEN x, GEN *c) sets c to content(x) and returns the primitive part x / c. A trivial content is set to NULL.

GEN primpart(GEN x) as above but the content is lost. (For efficiency, the content remains on the stack.)

## Over the rationals

long Q_pval(GEN x, GEN p) valuation at the t_INT p of the t_INT or t_FRAC x.

long Q_pvalrem(GEN x, GEN p, GEN *r) returns the valuation e at the t_INT p of the t_INT or t_FRAC x. The quotient x/p^{e} is returned in *r.

GEN Q_abs(GEN x) absolute value of the t_INT or t_FRAC x.

GEN Qdivii(GEN x, GEN y), assuming x and y are both of type t_INT, return the quotient x/y as a t_INT or t_FRAC; marginally faster than gdiv.

GEN Q_abs_shallow(GEN x) x being a t_INT or a t_FRAC, returns a shallow copy of |x|, in particular returns x itself when x >= 0, and gneg(x) otherwise.

GEN Q_gcd(GEN x, GEN y) gcd of the t_INT or t_FRAC x and y.

In the following functions, arguments belong to a M\otimes_ZQ for some natural Z-module M, e.g. multivariate polynomials with integer coefficients (or vectors/matrices recursively built from such objects), and an element of M is said to be integral. We are interested in contents, denominators, etc. with respect to this canonical integral structure; in particular, contents belong to Q, denominators to Z. For instance the Q-content of (1/2)xy is (1/2), and its Q-denominator is 2, whereas content would return y/2 and denom 1.

GEN Q_content(GEN x) the Q-content of x

GEN Q_denom(GEN x) the Q-denominator of x. Shallow function.

GEN Q_primitive_part(GEN x, GEN *c) sets c to the Q-content of x and returns x / c, which is integral.

GEN Q_primpart(GEN x) as above but the content is lost. (For efficiency, the content remains on the stack.)

GEN Q_remove_denom(GEN x, GEN *ptd) sets d to the Q-denominator of x and returns x * d, which is integral. Shallow function.

GEN Q_div_to_int(GEN x, GEN c) returns x / c, assuming c is a rational number (t_INT or t_FRAC) and the result is integral.

GEN Q_mul_to_int(GEN x, GEN c) returns x * c, assuming c is a rational number (t_INT or t_FRAC) and the result is integral.

GEN Q_muli_to_int(GEN x, GEN d) returns x * c, assuming c is a t_INT and the result is integral.

GEN mul_content(GEN cx, GEN cy) cx and cy are as set by primitive_part: either a GEN or NULL representing the trivial content 1. Returns their product (either a GEN or NULL).

GEN mul_denom(GEN dx, GEN dy) dx and dy are as set by Q_remove_denom: either a t_INT or NULL representing the trivial denominator 1. Returns their product (either a t_INT or NULL).

# Generic arithmetic operators

## Unary operators

GEN gneg[z](GEN x[, GEN z]) yields -x.

GEN gneg_i(GEN x) shallow function yielding -x.

GEN gabs[z](GEN x[, GEN z]) yields |x|.

GEN gsqr(GEN x) creates the square of x.

GEN ginv(GEN x) creates the inverse of x.

## Binary operators

Let op'' be a binary operation among

op = add: addition (x + y).

op = sub: subtraction (x - y).

op = mul: multiplication (x * y).

op = div: division (x / y).

@3The names and prototypes of the functions corresponding to op are as follows:

@3GEN gop(GEN x, GEN y)

@3GEN gopgs(GEN x, long s)

@3GEN gopsg(long s, GEN y)

@3Explicitly

GEN gadd(GEN x, GEN y), GEN gaddgs(GEN x, long s), GEN gaddsg(long s, GEN x)

GEN gmul(GEN x, GEN y), GEN gmulgs(GEN x, long s), GEN gmulsg(long s, GEN x)

GEN gsub(GEN x, GEN y), GEN gsubgs(GEN x, long s), GEN gsubsg(long s, GEN x)

GEN gdiv(GEN x, GEN y), GEN gdivgs(GEN x, long s), GEN gdivsg(long s, GEN x)

GEN gpow(GEN x, GEN y, long l) creates x^{y}. If y is a t_INT, return powgi(x,y) (the precision l is not taken into account). Otherwise, the result is exp (y* log (x)) where exact arguments are converted to floats of precision l in case of need; if there is no need, for instance if x is a t_REAL, l is ignored. Indeed, if x is a t_REAL, the accuracy of log  x is determined from the accuracy of x, it is no problem to multiply by y, even if it is an exact type, and the accuracy of the exponential is determined, exactly as in the case of the initial log  x.

GEN gpowgs(GEN x, long n) creates x^{n} using binary powering. To treat the special case n = 0, we consider gpowgs as a series of gmul, so we follow the rule of returning result which is as exact as possible given the input. More precisely, we return

@3* gen_1 if x has type t_INT, t_REAL, t_FRAC, or t_PADIC

@3* Mod(1,N) if x is a t_INTMOD modulo N.

@3* gen_1 for t_COMPLEX, t_QUAD unless one component is a t_INTMOD, in which case we return Mod(1, N) for a suitable N (the gcd of the moduli that appear).

@3* FF_1(x) for a t_FFELT.

@3* RgX_get_1(x) for a t_POL.

@3* qfi_1(x) and qfr_1(x) for t_QFI and t_QFR.

@3* the identity permutation for t_VECSMALL.

@3* etc.

Of course, the only practical use of this routine for n = 0 is to obtain the multiplicative neutral element in the base ring (or to treat marginal cases that should be special cased anyway if there is the slightest doubt about what the result should be).

GEN powgi(GEN x, GEN y) creates x^{y}, where y is a t_INT, using left-shift binary powering. The case where y = 0 (as all cases where y is small) is handled by gpowgs(x, 0).

GEN gpowers(GEN x, long n) returns the vector [1,x,...,x^n].

GEN grootsof1(long n, long prec) returns the vector [1,x,...,x^{n-1}], where x is the n-th root of unity exp (2ipi/n).

GEN gsqrpowers(GEN x, long n) returns the vector [x,x^4,...,x^{n^2}].

In addition we also have the obsolete forms:

void gaddz(GEN x, GEN y, GEN z)

void gsubz(GEN x, GEN y, GEN z)

void gmulz(GEN x, GEN y, GEN z)

void gdivz(GEN x, GEN y, GEN z)

# Generic operators: product, powering, factorback

To describe the following functions, we use the following private typedefs to simplify the description:

    typedef (*F0)(void *);
typedef (*F1)(void *, GEN);
typedef (*F2)(void *, GEN, GEN);

@3They correspond to generic functions with one and two arguments respectively (the void* argument provides some arbitrary evaluation context).

GEN gen_product(GEN v, void *D, F2 op) Given two objects x,y, assume that op(D, x, y) implements an associative binary operator. If v has k entries, return

v[1] op v[2] op ... op v[k];

returns gen_1 if k = 0 and a copy of v[1] if k = 1. Use divide and conquer strategy. Leave some garbage on stack, but suitable for gerepileupto if mul is.

GEN gen_pow(GEN x, GEN n, void *D, F1 sqr, F2 mul) n > 0 a t_INT, returns x^n; mul(D, x, y) implements the multiplication in the underlying monoid; sqr is a (presumably optimized) shortcut for mul(D, x, x).

GEN gen_powu(GEN x, ulong n, void *D, F1 sqr, F2 mul) n > 0, returns x^n. See gen_pow.

GEN gen_pow_i(GEN x, GEN n, void *E, F1 sqr, F2 mul) internal variant of gen_pow, not memory-clean.

GEN gen_powu_i(GEN x, ulong n, void *E, F1 sqr, F2 mul) internal variant of gen_powu, not memory-clean.

GEN gen_pow_fold(GEN x, GEN n, void *D, F1 sqr, F1 msqr) variant of gen_pow, where mul is replaced by msqr, with msqr(D, y) returning xy^2. In particular D must implicitly contain x.

GEN gen_pow_fold_i(GEN x, GEN n, void *E, F1 sqr, F1 msqr) internal variant of the function gen_pow_fold, not memory-clean.

GEN gen_powu_fold(GEN x, ulong n, void *D, F1 sqr, F1 msqr), see gen_pow_fold.

GEN gen_powu_fold_i(GEN x, ulong n, void *E, F1 sqr, F1 msqr) see gen_pow_fold_i.

GEN gen_powers(GEN x, long n, long usesqr, void *D, F1 sqr, F2 mul, F0 one) returns [x^0,..., x^n] as a t_VEC; mul(D, x, y) implements the multiplication in the underlying monoid; sqr is a (presumably optimized) shortcut for mul(D, x, x); one returns the monoid unit. The flag usesqr should be set to 1 if squaring are faster than multiplication by x.

GEN gen_factorback(GEN L, GEN e, F2 mul, F2 pow, void *D) generic form of factorback. The pair [L,e] is of the form

@3* [fa, NULL], fa a two-column factorization matrix: expand it.

@3* [v, NULL], v a vector of objects: return their product.

@3* or [v, e], v a vector of objects, e a vector of integral exponents: return the product of the v[i]^{e[i]}.

@3mul(D, x, y) and pow(D, x, n) return xy and x^n respectively.

# Matrix and polynomial norms

This section concerns only standard norms of R and C vector spaces, not algebraic norms given by the determinant of some multiplication operator. We have already seen type-specific functions like ZM_supnorm or RgM_fpnorml2 and limit ourselves to generic functions assuming nothing about their GEN argument; these functions allow the following scalar types: t_INT, t_FRAC, t_REAL, t_COMPLEX, t_QUAD and are defined recursively (in terms of norms of their components) for the following container'' types: t_POL, t_VEC, t_COL and t_MAT. They raise an error if some other type appears in the argument.

GEN gnorml2(GEN x) The norm of a scalar is the square of its complex modulus, the norm of a recursive type is the sum of the norms of its components. For polynomials, vectors or matrices of complex numbers one recovers the square of the usual L^2 norm. In most applications, the missing square root computation can be skipped.

GEN gnorml1(GEN x, long prec) The norm of a scalar is its complex modulus, the norm of a recursive type is the sum of the norms of its components. For polynomials, vectors or matrices of complex numbers one recovers the usual L^1 norm. One must include a real precision prec in case the inputs include t_COMPLEX or t_QUAD with exact rational components: a square root must be computed and we must choose an accuracy.

GEN gnorml1_fake(GEN x) as gnorml1, except that the norm of a t_QUAD x + wy or t_COMPLEX x + Iy is defined as |x| + |y|, where we use the ordinary real absolute value. This is still a norm of R vector spaces, which is easier to compute than gnorml1 and can often be used in its place.

GEN gsupnorm(GEN x, long prec) The norm of a scalar is its complex modulus, the norm of a recursive type is the max of the norms of its components. A precision prec must be included for the same reason as in gnorml1.

void gsupnorm_aux(GEN x, GEN *m, GEN *m2, long prec) is the low-level function underlying gsupnorm, used as follows:

    GEN m = NULL, m2 = NULL;
gsupnorm_aux(x, &m, &m2);

After the call, the sup norm of x is the min of m and the square root of m2; one or both of m, m2 may be NULL, in which case it must be omitted. You may initially set m and m2 to non-NULL values, in which case, the above procedure yields the max of (the initial) m, the square root of (the initial) m2, and the sup norm of x.

The strange interface is due to the fact that |z|^2 is easier to compute than |z| for a t_QUAD or t_COMPLEX z: m2 is the max of those |z|^2, and m is the max of the other |z|.

# Substitution and evaluation

GEN gsubst(GEN x, long v, GEN y) substitutes the object y into x for the variable number v.

GEN poleval(GEN q, GEN x) evaluates the t_POL or t_RFRAC q at x. For convenience, a t_VEC or t_COL is also recognized as the t_POL gtovecrev(q).

GEN RgX_cxeval(GEN T, GEN x, GEN xi) evaluate the t_POL T at x via Horner's scheme. If xi is not NULL it must be equal to 1/x and we evaluate x^{ deg  T}T(1/x) instead. This is useful when |x| > 1 is a t_REAL or an inexact t_COMPLEX and T has balanced'' coefficients, since the evaluation becomes numerically stable.

GEN RgX_RgM_eval(GEN q, GEN x) evaluates the t_POL q at the square matrix x.

GEN RgX_RgMV_eval(GEN f, GEN V) returns the evaluation f(x), assuming that V was computed by FpXQ_powers(x, n) for some n > 1.

GEN qfeval(GEN q, GEN x) evaluates the quadratic form q (symmetric matrix) at x (column vector of compatible dimensions).

GEN qfevalb(GEN q, GEN x, GEN y) evaluates the polar bilinear form attached to the quadratic form q (symmetric matrix) at x, y (column vectors of compatible dimensions).

GEN hqfeval(GEN q, GEN x) evaluates the Hermitian form q (a Hermitian complex matrix) at x.

GEN qf_apply_RgM(GEN q, GEN M) q is a symmetric n x n matrix, M an n x k matrix, return M' q M.

GEN qf_apply_ZM(GEN q, GEN M) as above assuming that both q and M have integer entries.

\newpage

# NAME

libPARI - Miscellaneous mathematical functions

# Fractions

GEN absfrac(GEN x) returns the absolute value of the t_FRAC x.

GEN absfrac_shallow(GEN x) x being a t_FRAC, returns a shallow copy of |x|, in particular returns x itself when x >= 0, and gneg(x) otherwise.

GEN sqrfrac(GEN x) returns the square of the t_FRAC x.

# Real numbers

GEN R_abs(GEN x) x being a t_INT, a t_REAL or a t_FRAC, returns |x|.

GEN R_abs_shallow(GEN x) x being a t_INT, a t_REAL or a t_FRAC, returns a shallow copy of |x|, in particular returns x itself when x >= 0, and gneg(x) otherwise.

GEN modRr_safe(GEN x, GEN y) let x be a t_INT, a t_REAL or t_FRAC and let y be a t_REAL. Return x% y unless the input accuracy is unsufficient to compute the floor or x/y in which case we return NULL.

# Complex numbers

GEN imag(GEN x) returns a copy of the imaginary part of x.

GEN real(GEN x) returns a copy of the real part of x. If x is a t_QUAD, returns the coefficient of 1 in the canonical'' integral basis (1,omega).

The last two functions are shallow, and not suitable for gerepileupto:

GEN imag_i(GEN x) as gimag, returns a pointer to the imaginary part. GEN real_i(GEN x) as greal, returns a pointer to the real part.

GEN mulreal(GEN x, GEN) returns the real part of xy; x,y have type t_INT, t_FRAC, t_REAL or t_COMPLEX. See also RgM_mulreal.

GEN cxnorm(GEN x) norm of the t_COMPLEX x (modulus squared).

GEN cxexpm1(GEN x) returns exp (x)-1, for a t_COMPLEX x.

GEN quad_disc(GEN x) returns the discriminant of the t_QUAD x.

GEN quadnorm(GEN x) norm of the t_QUAD x.

GEN qfb_disc(GEN x) returns the discriminant of the t_QFI or t_QFR x.

GEN qfb_disc3(GEN x, GEN y, GEN z) returns y^2 - 4xz assuming all inputs are t_INTs. Not stack-clean.

GEN qfb_apply_ZM(GEN q, GEN g) returns q o g.

GEN qfbforms(GEN D) given a discriminant D < 0, return the list of reduced forms of discriminant D as t_VECSMALL with 3 components. The primitive forms in the list enumerate the class group of the quadratic order of discriminant D; if D is fundamental, all returned forms are automatically primitive.

# Polynomials

GEN truecoeff(GEN x, long n) returns polcoeff0(x,n, -1), i.e. the coefficient of the term of degree n in the main variable.

GEN polcoeff_i(GEN x, long n, long v) internal shallow function. Rewrite x as a Laurent polynomial in the variable v and returns its coefficient of degree n (gen_0 if this falls outside the coefficient array). Allow t_POL, t_SER, t_RFRAC and scalars.

long degree(GEN x) returns poldegree(x, -1), the degree of x with respect to its main variable, with the usual meaning if the leading coefficient of x is non-zero. If the sign of x is 0, this function always returns -1. Otherwise, we return the index of the leading coefficient of x, i.e. the coefficient of largest index stored in x. For instance the degrees'' of

    0. E-38 * x^4 + 0.E-19 * x + 1
Mod(0,2) * x^0    \\ sign is 0 !

@3are 4 and -1 respectively.

long degpol(GEN x) is a simple macro returning lg(x) - 3. This is the degree of the t_POL x with respect to its main variable, if its leading coefficient is non-zero (a rational 0 is impossible, but an inexact 0 is allowed, as well as an exact modular 0, e.g. Mod(0,2)). If x has no coefficients (rational 0 polynomial), its length is 2 and we return the expected -1.

GEN characteristic(GEN x) returns the characteristic of the base ring over which the polynomial is defined (as defined by t_INTMOD and t_FFELT components). The function raises an exception if incompatible primes arise from t_FFELT and t_PADIC components. Shallow function.

GEN residual_characteristic(GEN x) returns a kind of residual characteristic'' of the base ring over which the polynomial is defined. This is defined as the gcd of all moduli t_INTMODs occurring in the structure, as well as primes p arising from t_PADICs or t_FFELTs. The function raises an exception if incompatible primes arise from t_FFELT and t_PADIC components. Shallow function.

GEN resultant(GEN x,GEN y) resultant of x and y, with respect to the main variable of highest priority. Uses either the subresultant algorithm (generic case), a modular algorithm (inputs in Q[X]) or Sylvester's matrix (inexact inputs).

GEN resultant2(GEN x, GEN y) resultant of x and y, with respect to the main variable of highest priority. Computes the determinant of Sylvester's matrix.

GEN resultant_all(GEN u, GEN v, GEN *sol) returns resultant(x,y). If sol is not NULL, sets it to the last non-constant remainder in the polynomial remainder sequence if such a sequence was computed, and to gen_0 otherwise (e.g. polynomials of degree 0, u,v in Q[X]).

GEN cleanroots(GEN x, long prec) returns the complex roots of the complex polynomial x (with coefficients t_INT, t_FRAC, t_REAL or t_COMPLEX of the above). The roots are returned as t_REAL or t_COMPLEX of t_REALs of precision prec (guaranteeing a non-0 imaginary part). See QX_complex_roots.

double fujiwara_bound(GEN x) return a quick upper bound for the logarithm in base 2 of the modulus of the largest complex roots of the polynomial x (complex coefficients).

double fujiwara_bound_real(GEN x, long sign) return a quick upper bound for the logarithm in base 2 of the absolute value of the largest real root of sign sign (1 or -1), for the polynomial x (real coefficients).

GEN polmod_to_embed(GEN x, long prec) return the vector of complex embeddings of the t_POLMOD x (with complex coefficients). Shallow function, simple complex variant of conjvec.

# Power series

GEN sertoser(GEN x, long prec) return the t_SER x truncated or extended (with zeros) to prec terms. Shallow function, assume that prec >= 0.

GEN derivser(GEN x) returns the derivative of the t_SER x with respect to its main variable.

GEN integser(GEN x) returns the primitive of the t_SER x with respect to its main variable.

GEN truecoeff(GEN x, long n) returns polcoeff0(x,n, -1), i.e. the coefficient of the term of degree n in the main variable.

GEN ser_unscale(GEN P, GEN h) return P(h x), not memory clean.

GEN ser_normalize(GEN x) divide x by its leading term'' so that the series is either 0 or equal to t^v(1+O(t)). Shallow function if the leading term'' is 1.

int ser_isexactzero(GEN x) return 1 if x is a zero series, all of whose known coefficients are exact zeroes; this implies that sign(x) = 0 and lg(x) <= 3.

GEN ser_inv(GEN x) return the inverse of the t_SER x using Newton iteration. This is in general slower than ginv unless the precision is huge (hundreds of terms, where the threshold depends strongly on the base field).

# Functions to handle t_FFELT

These functions define the public interface of the t_FFELT type to use in generic functions. However, in specific functions, it is better to use the functions class FpXQ and/or Flxq as appropriate.

GEN FF_p(GEN a) returns the characteristic of the definition field of the t_FFELT element a.

long FF_f(GEN a) returns the dimension of the definition field over its prime field; the cardinality of the dimension field is thus p^f.

GEN FF_p_i(GEN a) shallow version of FF_p.

GEN FF_q(GEN a) returns the cardinality of the definition field of the t_FFELT element a.

GEN FF_mod(GEN a) returns the polynomial (with reduced t_INT coefficients) defining the finite field, in the variable used to display a.

GEN FF_to_FpXQ(GEN a) converts the t_FFELT a to a polynomial P with reduced t_INT coefficients such that a = P(g) where g is the generator of the finite field returned by ffgen, in the variable used to display g.

GEN FF_to_FpXQ_i(GEN a) shallow version of FF_to_FpXQ.

GEN FF_to_F2xq(GEN a) converts the t_FFELT a to a F2x P such that a = P(g) where g is the generator of the finite field returned by ffgen, in the variable used to display g. This only work if the characteristic is 2.

GEN FF_to_F2xq_i(GEN a) shallow version of FF_to_F2xq.

GEN FF_to_Flxq(GEN a) converts the t_FFELT a to a Flx P such that a = P(g) where g is the generator of the finite field returned by ffgen, in the variable used to display g. This only work if the characteristic is small enough.

GEN FF_to_Flxq_i(GEN a) shallow version of FF_to_Flxq.

GEN p_to_FF(GEN p, long v) returns a t_FFELT equal to 1 in the finite field Z/pZ. Useful for generic code that wants to handle (inefficiently) Z/pZ as if it were not a prime field.

GEN Tp_to_FF(GEN T, GEN p) returns a t_FFELT equal to 1 in the finite field F_p/(T), where T is a ZX, assumed to be irreducible modulo p, or NULL in which case the routine acts as p_to_FF(p,0). No checks.

GEN Fq_to_FF(GEN x, GEN ff) returns a t_FFELT equal to x in the finite field defined by the t_FFELT ff, where x is an Fq (either a t_INT or a ZX: a t_POL with t_INT coefficients). No checks.

GEN FqX_to_FFX(GEN x, GEN ff) given an FqX x, return the polynomial with t_FFELT coefficients obtained by applying Fq_to_FF coefficientwise. No checks, and no normalization if the leading coefficient maps to 0.

GEN FF_1(GEN a) returns the unity in the definition field of the t_FFELT element a.

GEN FF_zero(GEN a) returns the zero element of the definition field of the t_FFELT element a.

int FF_equal0(GEN a) returns 1 if the t_FFELT a is equal to 0 else returns 0.

int FF_equal1(GEN a) returns 1 if the t_FFELT a is equal to 1 else returns 0.

int FF_equalm1(GEN a) returns -1 if the t_FFELT a is equal to 1 else returns 0.

int FF_equal(GEN a, GEN b) return 1 if the t_FFELT a and b have the same definition field and are equal, else 0.

int FF_samefield(GEN a, GEN b) return 1 if the t_FFELT a and b have the same definition field, else 0.

int Rg_is_FF(GEN c, GEN *ff) to be called successively on many objects, setting *ff = NULL (unset) initially. Returns 1 as long as c is a t_FFELT defined over the same field as *ff (setting *ff = c if unset), and 0 otherwise.

int RgC_is_FFC(GEN x, GEN *ff) apply Rg_is_FF successively to all components of the t_VEC or t_COL x. Return 0 if one call fails, and 1 otherwise.

int RgM_is_FFM(GEN x, GEN *ff) apply Rg_is_FF to all components of the t_MAT. Return 0 if one call fails, and 1 otherwise.

GEN FF_add(GEN a, GEN b) returns a+b where a and b are t_FFELT having the same definition field.

GEN FF_Z_add(GEN a, GEN x) returns a+x, where a is a t_FFELT, and x is a t_INT, the computation being performed in the definition field of a.

GEN FF_Q_add(GEN a, GEN x) returns a+x, where a is a t_FFELT, and x is a t_RFRAC, the computation being performed in the definition field of a.

GEN FF_sub(GEN a, GEN b) returns a-b where a and b are t_FFELT having the same definition field.

GEN FF_mul(GEN a, GEN b) returns a b where a and b are t_FFELT having the same definition field.

GEN FF_Z_mul(GEN a, GEN b) returns a b, where a is a t_FFELT, and b is a t_INT, the computation being performed in the definition field of a.

GEN FF_div(GEN a, GEN b) returns a/b where a and b are t_FFELT having the same definition field.

GEN FF_neg(GEN a) returns -a where a is a t_FFELT.

GEN FF_neg_i(GEN a) shallow function returning -a where a is a t_FFELT.

GEN FF_inv(GEN a) returns a^{-1} where a is a t_FFELT.

GEN FF_sqr(GEN a) returns a^2 where a is a t_FFELT.

GEN FF_mul2n(GEN a, long n) returns a 2^n where a is a t_FFELT.

GEN FF_pow(GEN x, GEN n) returns a^n where a is a t_FFELT andn is a t_INT.

GEN FF_Z_Z_muldiv(GEN a, GEN x, GEN y) returns a y/z, where a is a t_FFELT, and x and y are t_INT, the computation being performed in the definition field of a.

GEN Z_FF_div(GEN x, GEN a) return x/a where a is a t_FFELT, and x is a t_INT, the computation being performed in the definition field of a.

GEN FF_norm(GEN a) returns the norm of the t_FFELT a with respect to its definition field.

GEN FF_trace(GEN a) returns the trace of the t_FFELT a with respect to its definition field.

GEN FF_conjvec(GEN a) returns the vector of conjugates [a,a^p,a^{p^2},...,a^{p^{n-1}}] where the t_FFELT a belong to a field with p^n elements.

GEN FF_charpoly(GEN a) returns the characteristic polynomial) of the t_FFELT a with respect to its definition field.

GEN FF_minpoly(GEN a) returns the minimal polynomial of the t_FFELT a.

GEN FF_sqrt(GEN a) returns an t_FFELT b such that a = b^2 if it exist, where a is a t_FFELT.

long FF_issquareall(GEN x, GEN *pt) returns 1 if x is a square, and 0 otherwise. If x is indeed a square, set pt to its square root.

long FF_issquare(GEN x) returns 1 if x is a square and 0 otherwise.

long FF_ispower(GEN x, GEN K, GEN *pt) Given K a positive integer, returns 1 if x is a K-th power, and 0 otherwise. If x is indeed a K-th power, set pt to its K-th root.

GEN FF_sqrtn(GEN a, GEN n, GEN *zn) returns an n-th root of a if it exist. If zn is non-NULL set it to a primitive n-th root of the unity.

GEN FF_log(GEN a, GEN g, GEN o) the t_FFELT g being a generator for the definition field of the t_FFELT a, returns a t_INT e such that a^e = g. If e does not exists, the result is currently undefined. If o is not NULL it is assumed to be a factorization of the multiplicative order of g (as set by FF_primroot)

GEN FF_order(GEN a, GEN o) returns the order of the t_FFELT a. If o is non-NULL, it is assumed that o is a multiple of the order of a.

GEN FF_primroot(GEN a, GEN *o) returns a generator of the multiplicative group of the definition field of the t_FFELT a. If o is not NULL, set it to the factorization of the order of the primitive root (to speed up FF_log).

GEN FFX_factor(GEN f, GEN a) returns the factorization of the univariate polynomial f over the definition field of the t_FFELT a. The coefficients of f must be of type t_INT, t_INTMOD or t_FFELT and compatible with a.

GEN FFX_roots(GEN f, GEN a) returns the roots (t_FFELT) of the univariate polynomial f over the definition field of the t_FFELT a. The coefficients of f must be of type t_INT, t_INTMOD or t_FFELT and compatible with a.

GEN FFM_FFC_mul(GEN M, GEN C, GEN ff) returns the product of the matrix M (t_MAT) and the column vector C (t_COL) over the finite field given by ff (t_FFELT).

GEN FFM_ker(GEN M, GEN ff) returns the kernel of the t_MAT M defined over the finite field given by the t_FFELT ff (obtained by RgM_is_FFM(M,&ff)).

GEN FFM_det(GEN M, GEN ff)

GEN FFM_image(GEN M, GEN ff)

GEN FFM_inv(GEN M, GEN ff)

GEN FFM_mul(GEN M, GEN N, GEN ff) returns the product of the matrices M and N (t_MAT) over the finite field given by ff (t_FFELT).

long FFM_rank(GEN M, GEN ff)

# Transcendental functions

The following two functions are only useful when interacting with gp, to manipulate its internal default precision (expressed as a number of decimal digits, not in words as used everywhere else):

long getrealprecision(void) returns realprecision.

long setrealprecision(long n, long *prec) sets the new realprecision to n, which is returned. As a side effect, set prec to the corresponding number of words ndec2prec(n).

## Transcendental functions with t_REAL arguments

In the following routines, x is assumed to be a t_REAL and the result is a t_REAL (sometimes a t_COMPLEX with t_REAL components), with the largest accuracy which can be deduced from the input. The naming scheme is inconsistent here, since we sometimes use the prefix mp even though t_INT inputs are forbidden:

GEN sqrtr(GEN x) returns the square root of x.

GEN cbrtr(GEN x) returns the real cube root of x.

GEN sqrtnr(GEN x, long n) returns the n-th root of x, assuming n >= 1 and x > 0. Not stack clean.

GEN mpcos[z](GEN x[, GEN z]) returns cos (x).

GEN mpsin[z](GEN x[, GEN z]) returns sin (x).

GEN mplog[z](GEN x[, GEN z]) returns log (x). We must have x > 0 since the result must be a t_REAL. Use glog for the general case, where you want such computations as log (-1) = I.

GEN mpexp[z](GEN x[, GEN z]) returns exp (x).

GEN mpexpm1(GEN x) returns exp (x)-1, but is more accurate than subrs(mpexp(x), 1), which suffers from catastrophic cancellation if |x| is very small.

void mpsincosm1(GEN x, GEN *s, GEN *c) sets s and c to sin (x) and cos (x)-1 respectively, where x is a t_REAL; the latter is more accurate than subrs(mpcos(y), 1), which suffers from catastrophic cancellation if |x| is very small.

GEN mpveceint1(GEN C, GEN eC, long n) as veceint1; assumes that C > 0 is a t_REAL and that eC is NULL or mpexp(C).

GEN mpeint1(GEN x, GEN expx) returns eint1(x), for a t_REAL x >= 0, assuming that expx is mpexp(x).

GEN mplambertW(GEN y) solution x of the implicit equation x  exp (x) = y, for y > 0 a t_REAL.

@3Useful low-level functions which disregard the sign of x:

GEN sqrtr_abs(GEN x) returns sqrt {|x|} assuming x != 0.

GEN cbrtr_abs(GEN x) returns |x|^{1/3} assuming x != 0.

GEN exp1r_abs(GEN x) returns exp (|x|) - 1, assuming x != 0.

GEN logr_abs(GEN x) returns log (|x|), assuming x != 0.

## Other complex transcendental functions

GEN szeta(long s, long prec) returns the value of Riemann's zeta function at the (possibly negative) integer s != 1, in relative accuracy prec.

GEN veczeta(GEN a, GEN b, long N, long prec) returns in a vector all the zeta(aj + b), where j = 0, 1,..., N-1, where a and b are real numbers (of arbitrary type, although t_INT is treated more efficiently) and b > 1.

GEN ggamma1m1(GEN x, long prec) return Gamma(1+x) - 1 assuming |x| < 1. Guard against cancellation when x is small.

@3A few variants on sin and cos:

void mpsincos(GEN x, GEN *s, GEN *c) sets s and c to sin (x) and cos (x) respectively, where x is a t_REAL

GEN expIr(GEN x) returns exp (ix), where x is a t_REAL. The return type is t_COMPLEX unless the imaginary part is equal to 0 to the current accuracy (its sign is 0).

GEN expIxy(GEN x, GEN y, long prec) returns exp (ixy). Efficient when x is real and y pure imaginary.

void gsincos(GEN x, GEN *s, GEN *c, long prec) general case.

GEN rootsof1_cx(GEN d, long prec) return e(1/d) at precision prec, e(x) =  exp (2ipi x).

GEN rootsof1u_cx(ulong d, long prec) return e(1/d) at precision prec.

@3A generalization of affrr_fixlg

GEN affc_fixlg(GEN x, GEN res) assume res was allocated using cgetc, and that x is either a t_REAL or a t_COMPLEX with t_REAL components. Assign x to res, first shortening the components of res if needed (in a gerepile-safe way). Further convert res to a t_REAL if x is a t_REAL.

GEN trans_eval(const char *fun, GEN (*f) (GEN, long), GEN x, long prec) evaluate the transcendental function f (named "fun" at the argument x and precision prec. This is a quick way to implement a transcendental function to be made available under GP, starting from a C function handling only t_REAL and t_COMPLEX arguments. This routine first converts x to a suitable type:

@3* t_INT/t_FRAC to t_REAL of precision prec, t_QUAD to t_REAL or t_COMPLEX of precision prec.

@3* t_POLMOD to a t_COL of complex embeddings (as in conjvec)

Then evaluates the function at t_VEC, t_COL, t_MAT arguments coefficientwise.

## Transcendental functions with t_PADIC arguments

GEN Qp_exp(GEN x) shortcut for gexp(x, /*ignored*/prec)

GEN Qp_gamma(GEN x) shortcut for ggamma(x, /*ignored*/prec)

GEN Qp_log(GEN x) shortcut for glog(x, /*ignored*/prec)

GEN Qp_sqrt(GEN x) shortcut for gsqrt(x, /*ignored*/prec) Return NULL if x is not a square.

GEN Qp_sqrtn(GEN x, GEN n, GEN *z) shortcut for gsqrtn(x, n, z, /*ignored*/prec). Return NULL if x is not an n-th power.

## Cached constants

The cached constant is returned at its current precision, which may be larger than prec. One should always use the mpxxx variant: mppi, mpeuler, or mplog2.

GEN consteuler(long prec) precomputes Euler-Mascheroni's constant at precision prec.

GEN constcatalan(long prec) precomputes Catalan's constant at precision prec.

GEN constpi(long prec) precomputes pi at precision prec.

GEN constlog2(long prec) precomputes log (2) at precision prec.

void mpbern(long n, long prec) precomputes the n even Bernoulli numbers B_2,...,B_{2n} as t_FRAC or t_REALs of precision prec. For any 2 <= k <= 2n, if a floating point approximation of B_k to accuracy prec is enough to reconstruct it exactly, a t_FRAC is stored; otherwise a t_REAL at the requested accuracy. No more than n Bernoulli numbers will ever be stored (by bernfrac or bernreal), unless a subsequent call to mpbern increases the cache. If prec is 0, the B_k are computed exactly.

The following functions use cached data if prec is smaller than the precision of the cached value; otherwise the newly computed data replaces the old cache.

GEN mppi(long prec) returns pi at precision prec.

GEN Pi2n(long n, long prec) returns 2^npi at precision prec.

GEN PiI2(long n, long prec) returns the complex number 2pi i at precision prec.

GEN PiI2n(long n, long prec) returns the complex number 2^npi i at precision prec.

GEN mpeuler(long prec) returns Euler-Mascheroni's constant at precision prec.

GEN mpeuler(long prec) returns Catalan's number at precision prec.

GEN mplog2(long prec) returns log  2 at precision prec.

GEN bernreal(long i, long prec) returns the Bernoulli number B_i as a t_REAL at precision prec. If mpbern(n, p) was called previously with n >= i and p >= prec, then the cached value is (converted to a t_REAL of accuracy prec then) returned. Otherwise, the missing value is computed. In the latter case, if n >= i, the cached table is updated.

GEN bernfrac(long i) returns the Bernoulli number B_i as a rational number (t_FRAC or t_INT). If a cached table includes B_i as a rational number, the latter is returned. Otherwise, the missing value is computed. In the latter case, the cached Bernoulli table may be updated.

# Permutations

@3Permutation are represented in two different ways

@3* (perm) a t_VECSMALL p representing the bijection i:--->p[i]; unless mentioned otherwise, this is the form used in the functions below for both input and output,

@3* (cyc) a t_VEC of t_VECSMALLs representing a product of disjoint cycles.

GEN identity_perm(long n) return the identity permutation on n symbols.

GEN cyclic_perm(long n, long d) return the cyclic permutation mapping i to i+d (mod n) in S_n. Assume that d <= n.

GEN perm_mul(GEN s, GEN t) multiply s and t (composition s o t)

GEN perm_conj(GEN s, GEN t) return sts^{-1}.

int perm_commute(GEN p, GEN q) return 1 if p and q commute, 0 otherwise.

GEN perm_inv(GEN p) returns the inverse of p.

GEN perm_pow(GEN p, long n) returns p^n

GEN cyc_pow_perm(GEN p, long n) the permutation p is given as a product of disjoint cycles (cyc); return p^n (as a perm).

GEN cyc_pow(GEN p, long n) the permutation p is given as a product of disjoint cycles (cyc); return p^n (as a cyc).

GEN perm_cycles(GEN p) return the cyclic decomposition of p.

long perm_order(GEN p) returns the order of the permutation p (as the lcm of its cycle lengths).

GEN vecperm_orbits(GEN p, long n) the permutation p\in S_n being given as a product of disjoint cycles, return the orbits of the subgroup generated by p on {1,2,...,n}.

GEN Z_to_perm(long n, GEN x) as numtoperm, returning a t_VECSMALL.

GEN perm_to_Z(GEN v) as permtonum for a t_VECSMALL input.

# Small groups

The small (finite) groups facility is meant to deal with subgroups of Galois groups obtained by galoisinit and thus is currently limited to weakly super-solvable groups.

A group grp of order n is represented by its regular representation (for an arbitrary ordering of its element) in S_n. A subgroup of such group is represented by the restriction of the representation to the subgroup. A small group can be either a group or a subgroup. Thus it is embedded in some S_n, where n is the multiple of the order. Such an n is called the domain of the small group. The domain of a trivial subgroup cannot be derived from the subgroup data, so some functions require the subgroup domain as argument.

The small group grp is represented by a t_VEC with two components:

grp[1] is a generating subset [s_1,...,s_g] of grp expressed as a vector of permutations of length n.

grp[2] contains the relative orders [o_1,...,o_g] of the generators grp[1].

See galoisinit for the technical details.

GEN checkgroup(GEN gal, GEN *elts) checks whether gal is a small group or a Galois group. Returns the underlying small group and set elts to the list of elements or to NULL if it is not known.

GEN galois_group(GEN gal) return the underlying small group of the Galois group gal.

GEN cyclicgroup(GEN g, long s) returns the cyclic group with generator g of order s.

GEN trivialgroup(void) returns the trivial group.

GEN dicyclicgroup(GEN g1, GEN g2, long s1, long s2) returns the group with generators g1, g2 with respecting relative orders s1, s2.

GEN abelian_group(GEN v) let v be a t_VECSMALL seen as the SNF of a small abelian group, return its regular representation.

long group_domain(GEN grp) returns the domain of the non-trivial small group grp. Return an error if grp is trivial.

GEN group_elts(GEN grp, long n) returns the list of elements of the small group grp of domain n as permutations.

GEN group_set(GEN grp, long n) returns a F2v b such that b[i] is set if and only if the small group grp of domain n contains a permutation sending 1 to i.

GEN groupelts_set(GEN elts, long n), where elts is the list of elements of a small group of domain n, returns a F2v b such that b[i] is set if and only if the small group contains a permutation sending 1 to i.

long group_order(GEN grp) returns the order of the small group grp (which is the product of the relative orders).

long group_isabelian(GEN grp) returns 1 if the small group grp is Abelian, else 0.

GEN group_abelianHNF(GEN grp, GEN elts) if grp is not Abelian, returns NULL, else returns the HNF matrix of grp with respect to the generating family grp[1]. If elts is no NULL, it must be the list of elements of grp.

GEN group_abelianSNF(GEN grp, GEN elts) if grp is not Abelian, returns NULL, else returns its cyclic decomposition. If elts is no NULL, it must be the list of elements of grp.

long group_subgroup_isnormal(GEN G, GEN H), H being a subgroup of the small group G, returns 1 if H is normal in G, else 0.

long group_isA4S4(GEN grp) returns 1 if the small group grp is isomorphic to A_4, 2 if it is isomorphic to S_4 and 0 else. This is mainly to deal with the idiosyncrasy of the format.

GEN group_leftcoset(GEN G, GEN g) where G is a small group and g a permutation of the same domain, the left coset gG as a vector of permutations.

GEN group_rightcoset(GEN G, GEN g) where G is a small group and g a permutation of the same domain, the right coset Gg as a vector of permutations.

long group_perm_normalize(GEN G, GEN g) where G is a small group and g a permutation of the same domain, return 1 if gGg^{-1} = G, else 0.

GEN group_quotient(GEN G, GEN H), where G is a small group and H is a subgroup of G, returns the quotient map G-->G/H as an abstract data structure.

GEN quotient_perm(GEN C, GEN g) where C is the quotient map G-->G/H for some subgroup H of G and g an element of G, return the image of g by C (i.e. the coset gH).

GEN quotient_group(GEN C, GEN G) where C is the quotient map G-->G/H for some normal subgroup H of G, return the quotient group G/H as a small group.

GEN quotient_subgroup_lift(GEN C, GEN H, GEN S) where C is the quotient map G-->G/H for some group G normalizing H and S is a subgroup of G/H, return the inverse image of S by C.

GEN group_subgroups(GEN grp) returns the list of subgroups of the small group grp as a t_VEC.

GEN subgroups_tableset(GEN S, long n) where S is a vector of subgroups of domain n, returns a table which matchs the set of elements of the subgroups against the index of the subgroups.

long tableset_find_index(GEN tbl, GEN set) searchs the set set in the table tbl and returns its attached index, or 0 if not found.

GEN groupelts_abelian_group(GEN elts) where elts is the list of elements of an Abelian small group, returns the corresponding small group.

GEN groupelts_center(GEN elts) where elts is the list of elements of a small group, returns the list of elements of the center of the group.

GEN group_export(GEN grp, long format) exports a small group to another format, see galoisexport.

long group_ident(GEN grp, GEN elts) returns the index of the small group grp in the GAP4 Small Group library, see galoisidentify. If elts is not NULL, it must be the list of elements of grp.

long group_ident_trans(GEN grp, GEN elts) returns the index of the regular representation of the small group grp in the GAP4 Transitive Group library, see polgalois. If elts is no NULL, it must be the list of elements of grp.

\newpage

# NAME

libPARI - Standard data structures

# Character strings

## Functions returning a char *

char* pari_strdup(const char *s) returns a malloc'ed copy of s (uses pari_malloc).

char* pari_strndup(const char *s, long n) returns a malloc'ed copy of at most n chars from s (uses pari_malloc). If s is longer than n, only n characters are copied and a terminal null byte is added.

char* stack_strdup(const char *s) returns a copy of s, allocated on the PARI stack (uses stack_malloc).

char* stack_strcat(const char *s, const char *t) returns the concatenation of s and t, allocated on the PARI stack (uses stack_malloc).

char* stack_sprintf(const char *fmt, ...) runs pari_sprintf on the given arguments, returning a string allocated on the PARI stack.

char* itostr(GEN x) writes the t_INT x to a stack_malloc'ed string.

char* GENtostr(GEN x), using the current default output format (GP_DATA- > fmt, which contains the output style and the number of significant digits to print), converts x to a malloc'ed string. Simple variant of pari_sprintf.

char* GENtostr_raw(GEN x) as GENtostr with the following differences: 1) the output format is f_RAW; 2) the result is allocated on the stack and must not be freed.

char* GENtostr_unquoted(GEN x) as GENtostr_raw with the following additional difference: a t_STR x is printed without enclosing quotes (to be used by print.

char* GENtoTeXstr(GEN x), as GENtostr, except that f_TEX overrides the output format from GP_DATA- > fmt.

char* RgV_to_str(GEN g, long flag) g being a vector of GENs, returns a malloc'ed string, the concatenation of the GENtostr applied to its elements, except that t_STR are printed without enclosing quotes. flag determines the output format: f_RAW, f_PRETTYMAT or f_TEX.

## Functions returning a t_STR

GEN strtoGENstr(const char *s) returns a t_STR with content s.

GEN strntoGENstr(const char *s, long n) returns a t_STR containing the first n characters of s.

GEN chartoGENstr(char c) returns a t_STR containing the character c.

GEN GENtoGENstr(GEN x) returns a t_STR containing the printed form of x (in raw format). This is often easier to use that GENtostr (which returns a malloc-ed char*) since there is no need to free the string after use.

GEN GENtoGENstr_nospace(GEN x) as GENtoGENstr, removing all spaces from the output.

GEN Str(GEN g) as RgV_to_str with output format f_RAW, but returns a t_STR, not a malloc'ed string.

GEN Strtex(GEN g) as RgV_to_str with output format f_TEX, but returns a t_STR, not a malloc'ed string.

GEN Strexpand(GEN g) as RgV_to_str with output format f_RAW, performing tilde and environment expansion on the result. Returns a t_STR, not a malloc'ed string.

GEN gsprintf(const char *fmt, ...) equivalent to pari_sprintf(fmt,..., followed by strtoGENstr. Returns a t_STR, not a malloc'ed string.

GEN gvsprintf(const char *fmt, va_list ap) variadic version of gsprintf

# Output

## Output contexts

An output coutext, of type PariOUT, is a struct that models a stream and contains the following function pointers:

  void (*putch)(char);           /* fputc()-alike */
void (*puts)(const char*);     /* fputs()-alike */
void (*flush)(void);           /* fflush()-alike */

The methods putch and puts are used to print a character or a string respectively. The method flush is called to finalize a messages.

The generic functions pari_putc, pari_puts, pari_flush and pari_printf print according to a default output context, which should be sufficient for most purposes. Lower level functions are available, which take an explicit output context as first argument:

void out_putc(PariOUT *out, char c) essentially equivalent to out- > putc(c). In addition, registers whether the last character printed was a \n.

void out_puts(PariOUT *out, const char *s) essentially equivalent to out- > puts(s). In addition, registers whether the last character printed was a \n.

void out_printf(PariOUT *out, const char *fmt, ...)

void out_vprintf(PariOUT *out, const char *fmt, va_list ap)

@3N.B. The function out_flush does not exist since it would be identical to out- > flush()

int pari_last_was_newline(void) returns a non-zero value if the last character printed via out_putc or out_puts was \ n, and 0 otherwise.

void pari_set_last_newline(int last) sets the boolean value to be returned by the function pari_last_was_newline to last.

## Default output context

They are defined by the global variables pariOut and pariErr for normal outputs and warnings/errors, and you probably do not want to change them. If you do change them, diverting output in non-trivial ways, this probably means that you are rewriting gp. For completeness, we document in this section what the default output contexts do.

@3pariOut. writes output to the FILE* pari_outfile, initialized to stdout. The low-level methods are actually the standard putc / fputs, plus some magic to handle a log file if one is open.

@3pariErr. prints to the FILE* pari_errfile, initialized to stderr. The low-level methods are as above.

You can stick with the default pariOut output context and change PARI's standard output, redirecting pari_outfile to another file, using

void switchout(const char *name) where name is a character string giving the name of the file you want to write to; the output is appended at the end of the file. To close the file and revert to outputting to stdout, call switchout(NULL).

## PARI colors

In this section we describe the low-level functions used to implement GP's color scheme, attached to the colors default. The following symbolic names are attached to gp's output strings:

@3* c_ERR an error message

@3* c_HIST a history number (as in %1 = ...)

@3* c_PROMPT a prompt

@3* c_INPUT an input line (minus the prompt part)

@3* c_OUTPUT an output

@3* c_HELP a help message

@3* c_TIME a timer

@3* c_NONE everything else

If the colors default is set to a non-empty value, before gp outputs a string, it first outputs an ANSI colors escape sequence --- understood by most terminals ---, according to the colors specifications. As long as this is in effect, the following strings are rendered in color, possibly in bold or underlined.

void term_color(long c) prints (as if using pari_puts) the ANSI color escape sequence attached to output object c. If c is c_NONE, revert to default printing style.

void out_term_color(PariOUT *out, long c) as term_color, using output context out.

char* term_get_color(char *s, long c) returns as a character string the ANSI color escape sequence attached to output object c. If c is c_NONE, the value used to revert to default printing style is returned. The argument s is either NULL (string allocated on the PARI stack), or preallocated storage (in which case, it must be able to hold at least 16 chars, including the final \0).

## Obsolete output functions

These variants of void output(GEN x), which prints x, followed by a newline and a buffer flush are complicated to use and less flexible than what we saw above, or than the pari_printf variants. They are provided for backward compatibility and are scheduled to disappear.

void brute(GEN x, char format, long dec)

void matbrute(GEN x, char format, long dec)

void texe(GEN x, char format, long dec)

# Files

The following routines are trivial wrappers around system functions (possibly around one of several functions depending on availability). They are usually integrated within PARI's diagnostics system, printing messages if DEBUGFILES is high enough.

int pari_is_dir(const char *name) returns 1 if name points to a directory, 0 otherwise.

int pari_is_file(const char *name) returns 1 if name points to a directory, 0 otherwise.

int file_is_binary(FILE *f) returns 1 if the file f is a binary file (in the writebin sense), 0 otherwise.

void pari_unlink(const char *s) deletes the file named s. Warn if the operation fails.

void pari_fread_chars(void *b, size_t n, FILE *f) read n chars from stream f, storing the result in pre-allocated buffer b (assumed to be large enough).

char* path_expand(const char *s) perform tilde and environment expansion on s. Returns a malloc'ed buffer.

void strftime_expand(const char *s, char *buf, long max) perform time expansion on s, storing the result (at most max chars) in buffer buf. Trivial wrapper around

    time_t t = time(NULL);
strftime(but, max, s, localtime(&t);

char* pari_get_homedir(const char *user) expands ~ user constructs, returning the home directory of user user, or NULL if it could not be determined (in particular if the operating system has no such concept). The return value may point to static area and may be overwritten by subsequent system calls: use immediately or strdup it.

int pari_stdin_isatty(void) returns 1 if our standard input stdin is attached to a terminal. Trivial wrapper around isatty.

## pariFILE

PARI maintains a linked list of open files, to reclaim resources (file descriptors) on error or interrupts. The corresponding data structure is a pariFILE, which is a wrapper around a standard FILE*, containing further the file name, its type (regular file, pipe, input or output file, etc.). The following functions create and manipulate this structure; they are integrated within PARI's diagnostics system, printing messages if DEBUGFILES is high enough.

pariFILE* pari_fopen(const char *s, const char *mode) wrapper around fopen(s, mode), return NULL on failure.

pariFILE* pari_fopen_or_fail(const char *s, const char *mode) simple wrapper around fopen(s, mode); error on failure.

pariFILE* pari_fopengz(const char *s) opens the file whose name is s, and associates a (read-only) pariFILE with it. If s is a compressed file (.gz suffix), it is uncompressed on the fly. If s cannot be opened, also try to open s.gz. Returns NULL on failure.

void pari_fclose(pariFILE *f) closes the underlying file descriptor and deletes the pariFILE struct.

pariFILE* pari_safefopen(const char *s, const char *mode) creates a new file s (a priori for writing) with 600 permissions. Error if the file already exists. To avoid symlink attacks, a symbolic link exists, regardless of where it points to.

## Temporary files

PARI has its own idea of the system temp directory derived from an environment variable (GPTMPDIR, else TMPDIR), or the first writable directory among /tmp, /var/tmp and ..

char* pari_unique_dir(const char *s) creates a unique directory'' and return its name built from the string s, the user id and process pid (on Unix systems). This directory is itself located in the temp directory mentioned above. The name returned is malloc'ed.

char* pari_unique_filename(const char *s) creates a new empty file in the temp directory, whose name contains the id-string s (truncated to its first 8 chars), followed by a system-dependent suffix (incorporating the ids of both the user and the running process, for instance). The function returns the tempfile name. The name returned is malloc'ed.

# Errors

This section documents the various error classes, and the corresponding arguments to pari_err. The general syntax is

void pari_err(numerr,...)

@3In the sequel, we mostly use sequences of arguments of the form

    const char *s
const char *fmt, ...

@3where fmt is a PARI format, producing a string s from the remaining arguments. Since providing the correct arguments to pari_err is quite error-prone, we also provide specialized routines pari_err_ERRORCLASS(...) instead of pari_err(e_ERRORCLASS,...) so that the C compiler can check their arguments.

@3We now inspect the list of valid keywords (error classes) for numerr, and the corresponding required arguments.

## Internal errors, system'' errors

### e_ARCH A requested feature s is not available on this architecture or operating system.

    pari_err(e_ARCH)

@3prints the error message

sorry, 's' not available on this system.

### e_BUG A bug in the PARI library, in function s.

    pari_err(e_BUG, const char *s)
pari_err_BUG(const char *s)

@3prints the error message

Bug in s, please report.

### e_FILE Error while trying to open a file.

    pari_err(e_FILE, const char *what, const char *name)
pari_err_FILE(const char *what, const char *name)

@3prints the error message

error opening what: name'.

### e_IMPL A requested feature s is not implemented.

    pari_err(e_IMPL, const char *s)
pari_err_IMPL(const char *s)

@3prints the error message

sorry, s is not yet implemented.

### e_PACKAGE Missing optional package s.

    pari_err(e_PACKAGE, const char *s)
pari_err_PACKAGE(const char *s)

@3prints the error message

package s is required, please install it

## Syntax errors, type errors

### e_DIM arguments submitted to function s have inconsistent dimensions. E.g., when solving a linear system, or trying to compute the determinant of a non-square matrix.

    pari_err(e_DIM, const char *s)
pari_err_DIM(const char *s)

@3prints the error message

inconsistent dimensions in s.

### e_FLAG A flag argument is out of bounds in function s.

    pari_err(e_FLAG, const char *s)
pari_err_FLAG(const char *s)

@3prints the error message

invalid flag in s.

### e_NOTFUNC Generated by the PARI evaluator; tried to use a GEN which is not a t_CLOSURE in a function call syntax (as in f = 1; f(2);).

    pari_err(e_NOTFUNC, GEN fun)

@3prints the error message

not a function in a function call.

### e_OP Impossible operation between two objects than cannot be typecast to a sensible common domain for deeper reasons than a type mismatch, usually for arithmetic reasons. As in O(2) + O(3)

it is valid to add two t_PADICs, provided the underlying prime is the same; so the addition is not forbidden a priori for type reasons, it only becomes so when inspecting the objects and trying to perform the operation.

    pari_err(e_OP, const char *op, GEN x, GEN y)
pari_err_OP(const char *op, GEN x, GEN y)

@3As e_TYPE2, replacing forbidden by inconsistent.

### e_PRIORITY object o in function s contains variables whose priority is incompatible with the expected operation. E.g.Pol([x,1], 'y)

this raises an error because it's not possible to create a polynomial whose coefficients involve variables with higher priority than the main variable.

    pari_err(e_PRIORITY, const char *s, GEN o, const char *op, long v)
pari_err_PRIORITY(const char *s, GEN o, const char *op, long v)

@3prints the error message: incorrect priority in s, variable v_o op v, were v_o is gvar(o).

### e_SYNTAX Syntax error, generated by the PARI parser.

    pari_err(e_SYNTAX, const char *msg, const char *e, const char *entry)

@3where msg is a complete error message, and e and entry point into the same character string, which is the input that was incorrectly parsed

e points to the character where the parser failed, and entry <= e points somewhat before.

@3Prints the error message: msg, followed by a colon, then a part of the input character string (in general entry itself, but an initial segment may be truncated if e-entry is large); a caret points at e, indicating where the error took place.

### e_TYPE An argument x of function s had an unexpected type. (As in factor("blah").)

    pari_err(e_TYPE, const char *s, GEN x)
pari_err_TYPE(const char *s, GEN x)

@3prints the error message

incorrect type in s (t_x), where t_x is the type of x.

### e_TYPE2 Forbidden operation between two objects than cannot be typecast to a sensible common domain, because their types do not match up. (As in Mod(1,2) + Pi.)

    pari_err(e_TYPE2, const char *op, GEN x, GEN y)
pari_err_TYPE2(const char *op, GEN x, GEN y)

@3prints the error message

forbidden s t_x op t_y, where t_z denotes the type of z. Here, s denotes the spelled out name of the operator op\in{+, *, /, %, = }, e.g. addition for "+" or assignment for " = ". If op is not in the above operator, list, it is taken to be the already spelled out name of a function, e.g. "gcd", and the error message becomes forbidden op t_x, t_y.

### e_VAR polynomials x and y submitted to function s have inconsistent variables. E.g., considering the algebraic number Mod(t,t^2+1) in nfinit(x^2+1).

    pari_err(e_VAR, const char *s, GEN x, GEN y)
pari_err_VAR(const char *s, GEN x, GEN y)

@3prints the error message

inconsistent variables in s X != Y, where X and Y are the names of the variables of x and y, respectively.

## Overflows

### e_COMPONENT Trying to access an inexistent component in a vector/matrix/list in a function

the index is less than 1 or greater than the allowed length.

    pari_err(e_COMPONENT, const char *f, const char *op, GEN lim, GEN x)
pari_err_COMPONENT(const char *f, const char *op, GEN lim, GEN x)

@3prints the error message: non-existent component in f: index op lim. Special case: if f is the empty string (no meaningful public function name can be used), we ignore it and print the message: non-existent component: index op lim.

### e_DOMAIN An argument x is not in the function's domain (as in moebius(0) or zeta(1)).

    pari_err(e_DOMAIN, char *f, char *v, char *op, GEN lim, GEN x)
pari_err_DOMAIN(char *f, char *v, char *op, GEN lim, GEN x)

@3prints the error message

domain error in f: v op lim. Special case: if op is the empty string, we ignore lim and print the error message: domain error in f: v out of range.

### e_MAXPRIME A function using the precomputed list of prime numbers ran out of primes.

    pari_err(e_MAXPRIME, ulong c)
pari_err_MAXPRIME(ulong c)

@3prints the error message

not enough precomputed primes, need primelimit ~ c if c is non-zero. And simply not enough precomputed primes otherwise.

### e_MEM A call to pari_malloc or pari_realloc failed.

    pari_err(e_MEM)

@3prints the error message

not enough memory.

### e_OVERFLOW An object in function s becomes too large to be represented within PARI's hardcoded limits. (As in 2^2^2^10 or exp(1e100), which overflow in lg and expo.)

    pari_err(e_OVERFLOW, const char *s)
pari_err_OVERFLOW(const char *s)

@3prints the error message

overflow in s.

### e_PREC Function s fails because input accuracy is too low. (As in floor(1e100) at default accuracy.)

    pari_err(e_PREC, const char *s)
pari_err_PREC(const char *s)

@3prints the error message

precision too low in s.

### e_STACK The PARI stack overflows.

    pari_err(e_STACK)

@3prints the error message

the PARI stack overflows ! as well as some statistics concerning stack usage.

## Errors triggered intentionally

### e_ALARM A timeout, generated by the alarm function.

    pari_err(e_ALARM, const char *fmt, ...)

@3prints the error message

s.

### e_USER A user error, as triggered by error(g_1,...,g_n) in GP.

    pari_err(e_USER, GEN g)

@3prints the error message

user error:, then the entries of the vector g.

## Mathematical errors

### e_CONSTPOL An argument of function s is a constant polynomial, which does not make sense. (As in galoisinit(Pol(1)).)

    pari_err(e_CONSTPOL, const char *s)
pari_err_CONSTPOL(const char *s)

@3prints the error message

constant polynomial in s.

### e_COPRIME Function s expected two coprime arguments, and did receive x, y which were not.

    pari_err(e_COPRIME, const char *s, GEN x, GEN y)
pari_err_COPRIME(const char *s, GEN x, GEN y)

@3prints the error message

elements not coprime in s: x, y.

### e_INV Tried to invert a non-invertible object x.

    pari_err(e_INV, const char *s, GEN x)
pari_err_INV(const char *s, GEN x)

@3prints the error message

impossible inverse in s: x. If x = Mod(a,b) is a t_INTMOD and a is not 0 mod b, this allows to factor the modulus, as gcd(a,b) is a non-trivial divisor of b.

### e_IRREDPOL Function s expected an irreducible polynomial, and did not receive one. (As in nfinit(x^2-1).)

    pari_err(e_IRREDPOL, const char *s, GEN x)
pari_err_IRREDPOL(const char *s, GEN x)

@3prints the error message

not an irreducible polynomial in s: x.

### e_MISC Generic uncategorized error.

    pari_err(e_MISC, const char *fmt, ...)

@3prints the error message

s.

### e_MODULUS moduli x and y submitted to function s are inconsistent. E.g., considering the algebraic number Mod(t,t^2+1) in nfinit(t^3-2).

    pari_err(e_MODULUS, const char *s, GEN x, GEN y)
pari_err_MODULUS(const char *s, GEN x, GEN y)

@3prints the error message

inconsistent moduli in s, then the moduli.

### e_PRIME Function s expected a prime number, and did receive p, which was not. (As in idealprimedec(nf, 4).)

    pari_err(e_PRIME, const char *s, GEN x)
pari_err_PRIME(const char *s, GEN x)

@3prints the error message

not a prime in s: x.

### e_ROOTS0 An argument of function s is a zero polynomial, and we need to consider its roots. (As in polroots(0).)

    pari_err(e_ROOTS0, const char *s)
pari_err_ROOTS0(const char *s)

@3prints the error message

zero polynomial in s.

### e_SQRTN Tried to compute an n-th root of x, which does not exist, in function s. (As in sqrt(Mod(-1,3)).)

    pari_err(e_SQRTN, GEN x)
pari_err_SQRTN(GEN x)

@3prints the error message

not an n-th power residue in s: x.

## Miscellaneous functions

long name_numerr(const char *s) return the error number corresponding to an error name. E.g. name_numerr("e_DIM") returns e_DIM.

const char* numerr_name(long errnum) returns the error name corresponding to an error number. E.g. name_numerr(e_DIM) returns "e_DIM".

char* pari_err2str(GEN err) returns the error message that would be printed on t_ERROR err. The name is allocated on the PARI stack and must not be freed.

# Hashtables

A hashtable, or associative array, is a set of pairs (k,v) of keys and values. PARI implements general extensible hashtables for fast data retrieval: when creating a table, we may either choose to use the PARI stack, or malloc so as to be stack-independent. A hashtable is implemented as a table of linked lists, each list containing all entries sharing the same hash value. The table length is a prime number, which roughly doubles as the table overflows by gaining new entries; both the current number of entries and the threshold before the table grows are stored in the table. Finally the table remembers the functions used to hash the entries's keys and to test for equality two entries hashed to the same value.

An entry, or hashentry, contains

@3* a key/value pair (k,v), both of type void* for maximal flexibility,

@3* the hash value of the key, for the table hash function. This hash is mapped to a table index (by reduction modulo the table length), but it contains more information, and is used to bypass costly general equality tests if possible,

@3* a link pointer to the next entry sharing the same table cell.

  typedef struct {
void *key, *val;
ulong hash; /* hash(key) */
struct hashentry *next;
} hashentry;

typedef struct {
ulong len; /* table length */
hashentry **table; /* the table */
ulong nb, maxnb; /* number of entries stored and max nb before enlarging */
ulong pindex; /* prime index */
ulong (*hash) (void *k); /* hash function */
int (*eq) (void *k1, void *k2); /* equality test */
int use_stack; /* use the PARI stack, resp. malloc */
} hashtable;

@3

hashtable* hash_create(size, hash, eq, use_stack) \vskip -0.5em

    ulong size;
ulong (*hash)(void*);
int (*eq)(void*,void*);
int use_stack;

creates a hashtable with enough room to contain size entries. The functions hash and eq compute the hash value of keys and test keys for equality, respectively. If use_stack is non zero, the resulting table will use the PARI stack; otherwise, we use malloc.

hashtable* hash_create_ulong(ulong size, long stack) special case when the keys are ulongs with ordinary equality test.

hashtable* hash_create_str(ulong size, long stack) special case when the keys are character strings with string equality test (and hash_str hash function).

void hash_insert(hashtable *h, void *k, void *v) inserts (k,v) in hashtable h. No copy is made: k and v themselves are stored. The implementation does not prevent one to insert two entries with equal keys k, but which of the two is affected by later commands is undefined.

void hash_insert2(hashtable *h, void *k, void *v, ulong hash) as hash_insert, assuming h- > hash(k) is hash.

hashentry* hash_search(hashtable *h, void *k) look for an entry with key k in h. Return it if it one exists, and NULL if not.

hashentry* hash_search2(hashtable *h, void *k, ulong hash) as hash_search assuming h- > hash(k) is hash.

hashentry * hash_select(hashtable *h, void *k, void *E, int (*select)(void *, hashentry *)) variant of hash_search, useful when entries with identical keys are inserted: among the entries attached to key k, return one satisfying the selection criterion (such that select(E,e) is non-zero), or NULL if none exist.

hashentry* hash_remove(hashtable *h, void *k) deletes an entry (k,v) with key k from h and return it. (Return NULL if none was found.) Only the linking structures are freed, memory attached to k and v is not reclaimed.

hashentry* hash_remove_select(hashtable *h, void *k, void *E, int(*select)(void*, hashentry *)) a variant of hash_remove, useful when entries with identical keys are inserted: among the entries attached to key k, return one satisfying the selection criterion (such that select(E,e) is non-zero) and delete it, or NULL if none exist. Only the linking structures are freed, memory attached to k and v is not reclaimed.

GEN hash_keys(hashtable *h) return in a t_VECSMALL the keys stored in hashtable h.

GEN hash_values(hashtable *h) return in a t_VECSMALL the values stored in hashtable h.

void hash_destroy(hashtable *h) deletes the hashtable, by removing all entries.

void hash_dbg(hashtable *h) print statistics for hashtable h, allows to evaluate the attached hash function performance on actual data.

Some interesting hash functions are available:

ulong hash_str(const char *s)

ulong hash_str2(const char *s) is the historical PARI string hashing function and seems to be generally inferior to hash_str.

ulong hash_GEN(GEN x)

# Dynamic arrays

A dynamic array is a generic way to manage stacks of data that need to grow dynamically. It allocates memory using pari_malloc, and is independent of the PARI stack; it even works before the pari_init call.

## Initialization

To create a stack of objects of type foo, we proceed as follows:

  foo *t_foo;
pari_stack s_foo;
pari_stack_init(&s_foo, sizeof(*t_foo), (void**)t_foo);

@3Think of s_foo as the controlling interface, and t_foo as the (dynamic) array tied to it. The value of t_foo may be changed as you add more elements.

The following function pushes an element on the stack.

  /* access globals t_foo and s_foo */
void push_foo(foo x)
{
long n = pari_stack_new(&s_foo);
t_foo[n] = x;
}

## Accessing elements

Elements are accessed naturally through the t_foo pointer. For example this function swaps two elements:

  void swapfoo(long a, long b)
{
foo x;
if (a > s_foo.n || b > s_foo.n) pari_err_BUG("swapfoo");
x        = t_foo[a];
t_foo[a] = t_foo[b];
t_foo[b] = x;
}

## Stack of stacks

Changing the address of t_foo is not supported in general. In particular realloc()'ed array of stacks and stack of stacks are not supported.

## Public interface

Let s be a pari_stack and data the data linked to it. The following public fields are defined:

@3* s.alloc is the number of elements allocated for data.

@3* s.n is the number of elements in the stack and data[s.n-1] is the topmost element of the stack. s.n can be changed as long as 0 <= s.n <= s.alloc holds.

void pari_stack_init(pari_stack *s, size_t size, void **data) links *s to the data pointer *data, where size is the size of data element. The pointer *data is set to NULL, s- > n and s- > alloc are set to 0: the array is empty.

void pari_stack_alloc(pari_stack *s, long nb) makes room for nb more elements, i.e. makes sure that s.alloc >= s.n + nb, possibly reallocating data.

long pari_stack_new(pari_stack *s) increases s.n by one unit, possibly reallocating data, and returns s.n-1.

@3Caveat. The following construction is incorrect because stack_new can change the value of t_foo:

  t_foo[ pari_stack_new(&s_foo) ] = x;

void pari_stack_delete(pari_stack *s) frees data and resets the stack to the state immediately following stack_init (s- > n and s- > alloc are set to 0).

void * pari_stack_pushp(pari_stack *s, void *u) This function assumes that *data is of pointer type. Pushes the element u on the stack s.

void ** pari_stack_base(pari_stack *s) returns the address of data, typecast to a void **.

# Vectors and Matrices

## Access and extract

See "Label se:clean" and "Label se:unclean" for various useful constructors. Coefficients are accessed and set using gel, gcoeff, see "Label se:accessors". There are many internal functions to extract or manipulate subvectors or submatrices but, like the accessors above, none of them are suitable for gerepileupto. Worse, there are no type verification, nor bound checking, so use at your own risk.

GEN shallowcopy(GEN x) returns a GEN whose components are the components of x (no copy is made). The result may now be used to compute in place without destroying x. This is essentially equivalent to

    GEN y = cgetg(lg(x), typ(x));
for (i = 1; i < lg(x); i++) y[i] = x[i];
return y;

except that t_MAT is treated specially since shallow copies of all columns are made. The function also works for non-recursive types, but is useless in that case since it makes a deep copy. If x is known to be a t_MAT, you may call RgM_shallowcopy directly; if x is known not to be a t_MAT, you may call leafcopy directly.

GEN RgM_shallowcopy(GEN x) returns shallowcopy(x), where x is a t_MAT.

GEN shallowtrans(GEN x) returns the transpose of x, without copying its components, i. e., it returns a GEN whose components are (physically) the components of x. This is the internal function underlying gtrans.

GEN shallowconcat(GEN x, GEN y) concatenate x and y, without copying components, i. e., it returns a GEN whose components are (physically) the components of x and y.

GEN shallowconcat1(GEN x) x must be t_VEC or t_LIST, concatenate its elements from left to right. Shallow version of gconcat1.

GEN shallowmatconcat(GEN v) shallow version of matconcat.

GEN shallowextract(GEN x, GEN y) extract components of the vector or matrix x according to the selection parameter y. This is the shallow analog of extract0(x, y, NULL), see vecextract.

GEN RgM_minor(GEN A, long i, long j) given a square t_MAT A, return the matrix with i-th row and j-th column removed.

GEN vconcat(GEN A, GEN B) concatenate vertically the two t_MAT A and B of compatible dimensions. A NULL pointer is accepted for an empty matrix. See shallowconcat.

GEN matslice(GEN A, long a, long b, long c, long d) returns the submatrix A[a..b,c..d]. Assume a <= b and c <= d.

GEN row(GEN A, long i) return A[i,], the i-th row of the t_MAT A.

GEN row_i(GEN A, long i, long j1, long j2) return part of the i-th row of t_MAT A: A[i,j_1], A[i,j_1+1]...,A[i,j_2]. Assume j_1 <= j_2.

GEN rowcopy(GEN A, long i) return the row A[i,] of the t_MAT A. This function is memory clean and suitable for gerepileupto. See row for the shallow equivalent.

GEN rowslice(GEN A, long i1, long i2) return the t_MAT formed by the i_1-th through i_2-th rows of t_MAT A. Assume i_1 <= i_2.

GEN rowsplice(GEN A, long i) return the t_MAT formed from the coefficients of t_MAT A with j-th row removed.

GEN rowpermute(GEN A, GEN p), p being a t_VECSMALL representing a list [p_1,...,p_n] of rows of t_MAT A, returns the matrix whose rows are A[p_1,],..., A[p_n,].

GEN rowslicepermute(GEN A, GEN p, long x1, long x2), short for

    rowslice(rowpermute(A,p), x1, x2)

(more efficient).

GEN vecslice(GEN A, long j1, long j2), return A[j_1],..., A[j_2]. If A is a t_MAT, these correspond to columns of A. The object returned has the same type as A (t_VEC, t_COL or t_MAT). Assume j_1 <= j_2.

GEN vecsplice(GEN A, long j) return A with j-th entry removed (t_VEC, t_COL) or j-th column removed (t_MAT).

GEN vecreverse(GEN A). Returns a GEN which has the same type as A (t_VEC, t_COL or t_MAT), and whose components are the A[n],...,A[1]. If A is a t_MAT, these are the columns of A.

void vecreverse_inplace(GEN A) as vecreverse, but reverse A in place.

GEN vecpermute(GEN A, GEN p) p is a t_VECSMALL representing a list [p_1,...,p_n] of indices. Returns a GEN which has the same type as A (t_VEC, t_COL or t_MAT), and whose components are A[p_1],...,A[p_n]. If A is a t_MAT, these are the columns of A.

GEN vecsmallpermute(GEN A, GEN p) as vecpermute when A is a t_VECSMALL.

GEN vecslicepermute(GEN A, GEN p, long y1, long y2) short for

    vecslice(vecpermute(A,p), y1, y2)

(more efficient).

## Componentwise operations

The following convenience routines automate trivial loops of the form

    for (i = 1; i < lg(a); i++) gel(v,i) = f(gel(a,i), gel(b,i))

for suitable f:

GEN vecinv(GEN a). Given a vector a, returns the vector whose i-th component is ginv(a[i]).

GEN vecmul(GEN a, GEN b). Given a and b two vectors of the same length, returns the vector whose i-th component is gmul(a[i], b[i]).

GEN vecdiv(GEN a, GEN b). Given a and b two vectors of the same length, returns the vector whose i-th component is gdiv(a[i], b[i]).

GEN vecpow(GEN a, GEN n). Given n a t_INT, returns the vector whose i-th component is a[i]^n.

GEN vecmodii(GEN a, GEN b). Assuming a and b are two ZV of the same length, returns the vector whose i-th component is modii(a[i], b[i]).

Note that vecadd or vecsub do not exist since gadd and gsub have the expected behavior. On the other hand, ginv does not accept vector types, hence vecinv.

## Low-level vectors and columns functions

These functions handle t_VEC as an abstract container type of GENs. No specific meaning is attached to the content. They accept both t_VEC and t_COL as input, but col functions always return t_COL and vec functions always return t_VEC.

@3Note. All the functions below are shallow.

GEN const_col(long n, GEN x) returns a t_COL of n components equal to x.

GEN const_vec(long n, GEN x) returns a t_VEC of n components equal to x.

int vec_isconst(GEN v) Returns 1 if all the components of v are equal, else returns 0.

void vec_setconst(GEN v, GEN x) v a pre-existing vector. Set all its components to x.

int vec_is1to1(GEN v) Returns 1 if the components of v are pair-wise distinct, i.e. if i:--->v[i] is a 1-to-1 mapping, else returns 0.

GEN vec_append(GEN V, GEN s) append s to the vector V.

GEN vec_shorten(GEN v, long n) shortens the vector v to n components.

GEN vec_lengthen(GEN v, long n) lengthens the vector v to n components. The extra components are not initialized.

GEN vec_insert(GEN v, long n, GEN x) inserts x at position n in the vector v.

# Vectors of small integers

## t_VECSMALL

These functions handle t_VECSMALL as an abstract container type of small signed integers. No specific meaning is attached to the content.

GEN const_vecsmall(long n, long c) returns a t_VECSMALL of n components equal to c.

GEN vec_to_vecsmall(GEN z) identical to ZV_to_zv(z).

GEN vecsmall_to_vec(GEN z) identical to zv_to_ZV(z).

GEN vecsmall_to_col(GEN z) identical to zv_to_ZC(z).

GEN vecsmall_copy(GEN x) makes a copy of x on the stack.

GEN vecsmall_shorten(GEN v, long n) shortens the t_VECSMALL v to n components.

GEN vecsmall_lengthen(GEN v, long n) lengthens the t_VECSMALL v to n components. The extra components are not initialized.

GEN vecsmall_indexsort(GEN x) performs an indirect sort of the components of the t_VECSMALL x and return a permutation stored in a t_VECSMALL.

void vecsmall_sort(GEN v) sorts the t_VECSMALL v in place.

void vecsmall_reverse(GEN v) as vecreverse for a t_VECSMALL v.

long vecsmall_max(GEN v) returns the maximum of the elements of t_VECSMALL v, assumed non-empty.

long vecsmall_indexmax(GEN v) returns the index of the largest element of t_VECSMALL v, assumed non-empty.

long vecsmall_min(GEN v) returns the minimum of the elements of t_VECSMALL v, assumed non-empty.

long vecsmall_indexmin(GEN v) returns the index of the smallest element of t_VECSMALL v, assumed non-empty.

long vecsmall_isin(GEN v, long x) returns the first index i such that v[i] is equal to x. Naive search in linear time, does not assume that v is sorted.

GEN vecsmall_uniq(GEN v) given a t_VECSMALL v, return the vector of unique occurrences.

GEN vecsmall_uniq_sorted(GEN v) same as vecsmall_uniq, but assumes v sorted.

long vecsmall_duplicate(GEN v) given a t_VECSMALL v, return 0 if there is no duplicates, or the index of the first duplicate (vecsmall_duplicate([1,1]) returns 2).

long vecsmall_duplicate_sorted(GEN v) same as vecsmall_duplicate, but assume v sorted.

int vecsmall_lexcmp(GEN x, GEN y) compares two t_VECSMALL lexically.

int vecsmall_prefixcmp(GEN x, GEN y) truncate the longest t_VECSMALL to the length of the shortest and compares them lexicographically.

GEN vecsmall_prepend(GEN V, long s) prepend s to the t_VECSMALL V.

GEN vecsmall_append(GEN V, long s) append s to the t_VECSMALL V.

GEN vecsmall_concat(GEN u, GEN v) concat the t_VECSMALL u and v.

long vecsmall_coincidence(GEN u, GEN v) returns the numbers of indices where u and v agree.

long vecsmall_pack(GEN v, long base, long mod) handles the t_VECSMALL v as the digit of a number in base base and return this number modulo mod. This can be used as an hash function.

## Vectors of t_VECSMALL

These functions manipulate vectors of t_VECSMALL (vecvecsmall).

GEN vecvecsmall_sort(GEN x) sorts lexicographically the components of the vector x.

GEN vecvecsmall_sort_uniq(GEN x) sorts lexicographically the components of the vector x, removing duplicates entries.

GEN vecvecsmall_indexsort(GEN x) performs an indirect lexicographic sorting of the components of the vector x and return a permutation stored in a t_VECSMALL.

long vecvecsmall_search(GEN x, GEN y, long flag) x being a sorted vecvecsmall and y a t_VECSMALL, search y inside x. flag has the same meaning as for setsearch.

\newpage

# NAME

libPARI - Functions related to the GP interpreter

# Handling closures

## Functions to evaluate t_CLOSURE

void closure_disassemble(GEN C) print the t_CLOSURE C in GP assembly format.

GEN closure_callgenall(GEN C, long n, ...) evaluate the t_CLOSURE C with the n arguments (of type GEN) following n in the function call. Assumes C has arity  >= n.

GEN closure_callgenvec(GEN C, GEN args) evaluate the t_CLOSURE C with the arguments supplied in the vector args. Assumes C has arity  >= lg(args)-1.

GEN closure_callgenvecprec(GEN C, GEN args, long prec) as closure_callgenvec but set the precision locally to prec.

GEN closure_callgen1(GEN C, GEN x) evaluate the t_CLOSURE C with argument x. Assumes C has arity  >= 1.

GEN closure_callgen1prec(GEN C, GEN x, long prec) as closure_callgen1, but set the precision locally to prec.

GEN closure_callgen2(GEN C, GEN x, GEN y) evaluate the t_CLOSURE C with argument x, y. Assumes C has arity  >= 2.

void closure_callvoid1(GEN C, GEN x) evaluate the t_CLOSURE C with argument x and discard the result. Assumes C has arity  >= 1.

The following technical functions are used to evaluate inline closures and closures of arity 0.

The control flow statements (break, next and return) will cause the evaluation of the closure to be interrupted; this is called below a flow change. When that occurs, the functions below generally return NULL. The caller can then adopt three positions:

@3* raises an exception (closure_evalnobrk).

@3* passes through (by returning NULL itself).

@3* handles the flow change.

GEN closure_evalgen(GEN code) evaluates a closure and returns the result, or NULL if a flow change occurred.

GEN closure_evalnobrk(GEN code) as closure_evalgen but raise an exception if a flow change occurs. Meant for iterators where interrupting the closure is meaningless, e.g. intnum or sumnum.

void closure_evalvoid(GEN code) evaluates a closure whose return value is ignored. The caller has to deal with eventual flow changes by calling loop_break.

The remaining functions below are for exceptional situations:

GEN closure_evalres(GEN code) evaluates a closure and returns the result. The difference with closure_evalgen being that, if the flow end by a return statement, the result will be the returned value instead of NULL. Used by the main GP loop.

GEN closure_evalbrk(GEN code, long *status) as closure_evalres but set status to a non-zero value if a flow change occurred. This variant is not stack clean. Used by the break loop.

GEN closure_trapgen(long numerr, GEN code) evaluates closure, while trapping error numerr. Return (GEN)1L if error trapped, and the result otherwise, or NULL if a flow change occurred. Used by trap.

## Functions to handle control flow changes

long loop_break(void) processes an eventual flow changes inside an iterator. If this function return 1, the iterator should stop.

## Functions to deal with lexical local variables

Function using the prototype code V' need to manually create and delete a lexical variable for each code V', which will be given a number -1, -2, ....

void push_lex(GEN a, GEN code) creates a new lexical variable whose initial value is a on the top of the stack. This variable get the number -1, and the number of the other variables is decreased by one unit. When the first variable of a closure is created, the argument code must be the closure that references this lexical variable. The argument code must be NULL for all subsequent variables (if any). (The closure contains the debugging data for the variable).

void pop_lex(long n) deletes the n topmost lexical variables, increasing the number of other variables by n. The argument n must match the number of variables allocated through push_lex.

GEN get_lex(long vn) get the value of the variable with number vn.

void set_lex(long vn, GEN x) set the value of the variable with number vn.

## Functions returning new closures

GEN compile_str(const char *s) returns the closure corresponding to the GP expression s.

GEN closure_deriv(GEN code) returns a closure corresponding to the numerical derivative of the closure code.

GEN snm_closure(entree *ep, GEN data) Let data be a vector of length m, ep be an entree pointing to a C function f of arity n+m, returns a t_CLOSURE object g of arity n such that g(x_1,...,x_n) = f(x_1,...,x_n,gel(data,1),...,gel(data,m)). If data is NULL, then m = 0 is assumed. This function has a low overhead since it does not copy data.

GEN strtofunction(char *str) returns a closure corresponding to the built-in or install'ed function named str.

GEN strtoclosure(char *str, long n, ...) returns a closure corresponding to the built-in or install'ed function named str with the n last parameters set to the n GENs following n, see snm_closure. This function has an higher overhead since it copies the parameters and does more input validation.

In the example code below, agm1 is set to the function x- > agm(x,1) and res is set to agm(2,1).

    GEN agm1 = strtoclosure("agm",1, gen_1);
GEN res = closure_callgen1(agm1, gen_2);

## Functions used by the gp debugger (break loop)

long closure_context(long s) restores the compilation context starting at frame s+1, and returns the index of the topmost frame. This allow to compile expressions in the topmost lexical scope.

void closure_err(void) prints a backtrace of the last 20 stack frames.

## Standard wrappers for iterators

Two families of standard wrappers are provided to interface iterators like intnum or sumnum with GP.

### Standard wrappers for inline closures

Theses wrappers are used to implement GP functions taking inline closures as input. The object (GEN)E must be an inline closure which is evaluated with the lexical variable number -1 set to x.

GEN gp_eval(void *E, GEN x) is used for the prototype code E'.

GEN gp_evalprec(void *E, GEN x, long prec) as gp_eval, but set the precision locally to prec.

long gp_evalvoid(void *E, GEN x) is used for the prototype code I'. The resulting value is discarded. Return a non-zero value if a control-flow instruction request the iterator to terminate immediately.

long gp_evalbool(void *E, GEN x) returns the boolean gp_eval(E, x) evaluates to (i.e. true iff the value is non-zero).

GEN gp_evalupto(void *E, GEN x) memory-safe version of gp_eval, gcopy-ing the result, when the evaluator returns components of previously allocated objects (e.g. member functions).

### Standard wrappers for true closures

These wrappers are used to implement GP functions taking true closures as input.

GEN gp_call(void *E, GEN x) evaluates the closure (GEN)E on x.

GEN gp_callprec(void *E, GEN x, long prec) as gp_call, but set the precision locally to prec.

GEN gp_call2(void *E, GEN x, GEN y) evaluates the closure (GEN)E on (x,y).

long gp_callbool(void *E, GEN x) evaluates the closure (GEN)E on x, returns 1 if its result is non-zero, and 0 otherwise.

long gp_callvoid(void *E, GEN x) evaluates the closure (GEN)E on x, discarding the result. Return a non-zero value if a control-flow instruction request the iterator to terminate immediately.

# Defaults

entree* pari_is_default(const char *s) return the entree structure attached to s if it is the name of a default, NULL otherwise.

GEN setdefault(const char *s, const char *v, long flag) is the low-level function underlying default0. If s is NULL, call all default setting functions with string argument NULL and flag d_ACKNOWLEDGE. Otherwise, check whether s corresponds to a default and call the corresponding default setting function with arguments v and flag.

We shall describe these functions below: if v is NULL, we only look at the default value (and possibly print or return it, depending on flag); otherwise the value of the default to v, possibly after some translation work. The flag is one of

@3* d_INITRC called while reading the gprc: print and return gnil, possibly defer until gp actually starts.

@3* d_RETURN return the current value, as a t_INT if possible, as a t_STR otherwise.

@3* d_ACKNOWLEDGE print the current value, return gnil.

@3* d_SILENT print nothing, return gnil.

@3Low-level functions called by setdefault:

GEN sd_TeXstyle(const char *v, long flag)

GEN sd_breakloop(const char *v, long flag)

GEN sd_colors(const char *v, long flag)

GEN sd_compatible(const char *v, long flag)

GEN sd_datadir(const char *v, long flag)

GEN sd_debug(const char *v, long flag)

GEN sd_debugfiles(const char *v, long flag)

GEN sd_debugmem(const char *v, long flag)

GEN sd_echo(const char *v, long flag)

GEN sd_factor_add_primes(const char *v, long flag)

GEN sd_factor_proven(const char *v, long flag)

GEN sd_format(const char *v, long flag)

GEN sd_graphcolormap(const char *v, long flag)

GEN sd_graphcolors(const char *v, long flag)

GEN sd_help(const char *v, long flag)

GEN sd_histfile(const char *v, long flag)

GEN sd_histsize(const char *v, long flag)

GEN sd_lines(const char *v, long flag)

GEN sd_linewrap(const char *v, long flag)

GEN sd_log(const char *v, long flag)

GEN sd_logfile(const char *v, long flag)

GEN sd_nbthreads(const char *v, long flag)

GEN sd_new_galois_format(const char *v, long flag)

GEN sd_output(const char *v, long flag)

GEN sd_parisize(const char *v, long flag)

GEN sd_parisizemax(const char *v, long flag)

GEN sd_path(const char *v, long flag)

GEN sd_prettyprinter(const char *v, long flag)

GEN sd_primelimit(const char *v, long flag)

GEN sd_prompt(const char *v, long flag)

GEN sd_prompt_cont(const char *v, long flag)

GEN sd_psfile(const char *v, long flag)

GEN sd_readline(const char *v, long flag)

GEN sd_realbitprecision(const char *v, long flag)

GEN sd_realprecision(const char *v, long flag)

GEN sd_recover(const char *v, long flag)

GEN sd_secure(const char *v, long flag)

GEN sd_seriesprecision(const char *v, long flag)

GEN sd_simplify(const char *v, long flag)

GEN sd_sopath(const char *v, int flag)

GEN sd_strictargs(const char *v, long flag)

GEN sd_strictmatch(const char *v, long flag)

GEN sd_timer(const char *v, long flag)

GEN sd_threadsize(const char *v, long flag)

GEN sd_threadsizemax(const char *v, long flag)

@3Generic functions used to implement defaults: most of the above routines are implemented in terms of the following generic ones. In all routines below

@3* v and flag are the arguments passed to default: v is a new value (or the empty string: no change), and flag is one of d_INITRC, d_RETURN, etc.

@3* s is the name of the default being changed, used to display error messages or acknowledgements.

GEN sd_toggle(const char *v, long flag, const char *s, int *ptn)

@3* if v is neither "0" nor "1", an error is raised using pari_err.

@3* ptn points to the current numerical value of the toggle (1 or 0), and is set to the new value (when v is non-empty).

For instance, here is how the timer default is implemented internally:

  GEN
sd_timer(const char *v, long flag)
{ return sd_toggle(v,flag,"timer", &(GP_DATA->chrono)); }

The exact behavior and return value depends on flag:

@3* d_RETURN: returns the new toggle value, as a GEN.

@3* d_ACKNOWLEDGE: prints a message indicating the new toggle value and return gnil.

@3* other cases: print nothing and return gnil.

GEN sd_ulong(const char *v, long flag, const char *s, ulong *ptn, ulong Min, ulong Max, const char **msg)\hbadness 10000

@3* ptn points to the current numerical value of the toggle, and is set to the new value (when v is non-empty).

@3* Min and Max point to the minimum and maximum values allowed for the default.

@3* v must translate to an integer in the allowed ranger, a suffix among k/K ( x 10^3), m/M ( x 10^6), or g/G ( x 10^9) is allowed, but no arithmetic expression.

@3* msg is a \kbd[NULL]-terminated array of messages or NULL (ignored). If msg is not NULL, msg[i] contains a message attached to the value i of the default. The last entry in the msg array is used as a message attached to all subsequent ones.

The exact behavior and return value depends on flag:

@3* d_RETURN: returns the new toggle value, as a GEN.

@3* d_ACKNOWLEDGE: prints a message indicating the new value, possibly a message attached to it via the msg argument, and return gnil.

@3* other cases: print nothing and return gnil.

GEN sd_string(const char *v, long flag, const char *s, char **pstr) * v is subjet to environment expansion, then time expansion.

@3* pstr points to the current string value, and is set to the new value (when v is non-empty).

# Records and Lazy vectors

The functions in this section are used to implement ell structures and analogous objects, which are vectors some of whose components are initialized to dummy values, later computed on demand. We start by initializing the structure:

GEN obj_init(long d, long n) returns an obj S, a t_VEC with d regular components, accessed as gel(S,1),..., gel(S,d); together with a record of n members, all initialized to 0. The arguments d and n must be non-negative.

After S = obj_init(d, n), the prototype of our other functions are of the form

    GEN obj_do(GEN S, long tag, ...)

@3The first argument S holds the structure to be managed. The second argument tag is the index of the struct member (from 1 to n) we operate on. We recommend to define an enum and use descriptive names instead of hardcoded numbers. For instance, if n = 3, after defining

    enum { TAG_p = 1, TAG_list, TAG_data };

@3one may use TAG_list or 2 indifferently as a tag. The former being preferred, of course.

@3Technical note. In the current implementation, S is a t_VEC with d+1 entries. The first d components are ordinary t_GEN entries, which you can read or assign to in the customary way. But the last component gel(S, d+1), a t_VEC of length n initialized to zerovec(n), must be handled in a special way: you should never access or modify its components directly, only through the API we are about to describe. Indeed, its entries are meant to contain dynamic data, which will be stored, retrieved and replaced (for instance by a value computed to a higher accuracy), while interacting safely with intermediate gerepile calls. This mechanism allows to simulate C structs, in a simpler way than with general hashtables, while remaining compatible with the GP language, which knows neither structs nor hashtables. It also serialize the structure in an ordinary GEN, which facilitates copies and garbage collection (use gcopy or gerepile), rather than having to deal with individual components of actual C structs.

GEN obj_reinit(GEN S) make a shallow copy of S, re-initializing all dynamic components. This allows forking'' a lazy vector while avoiding both a memory leak, and storing pointers to the same data in different objects (with risks of a double free later).

GEN obj_check(GEN S, long tag) if the tag-component in S is non empty, return it. Otherwise return NULL. The t_INT 0 (initial value) is used as a sentinel to indicated an empty component.

GEN obj_insert(GEN S, long tag, GEN O) insert (a clone of) O as tag-component of S. Any previous value is deleted, and data pointing to it become invalid.

GEN obj_insert_shallow(GEN S, long K, GEN O) as obj_insert, inserting O as-is, not via a clone.

GEN obj_checkbuild(GEN S, long tag, GEN (*build)(GEN)) if the tag-component of S is non empty, return it. Otherwise insert (a clone of) build(S) as tag-component in S, and return it.

GEN obj_checkbuild_padicprec(GEN S, long tag, GEN (*build)(GEN,long), long prec) if the tag-component of S is non empty and has relative p-adic precision  >= prec, return it. Otherwise insert (a clone of) build(S, prec) as tag-component in S, and return it.

GEN obj_checkbuild_realprec(GEN S, long tag, GEN (*build)(GEN, long), long prec) if the tag-component of S is non empty and satisfies gprecision  >= prec, return it. Otherwise insert (a clone of) build(S, prec) as tag-component in S, and return it.

GEN obj_checkbuild_prec(GEN S, long tag, GEN (*build)(GEN,long), GEN (*gpr)(GEN), long prec) if the tag-component of S is non empty and has precision gpr(x) >= prec, return it. Otherwise insert (a clone of) build(S, prec) as tag-component in S, and return it.

void obj_free(GEN S) destroys all clones stored in the n tagged components, and replace them by the initial value 0. The regular entries of S are unaffected, and S` remains a valid object. This is used to avoid memory leaks.