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.
The following functions enable you to start using the PARI functions in a program, and cleanup without exiting the whole program.
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.
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)
.
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.
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.
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.
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.
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.
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.
GEN
s@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.
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_REAL
s 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.
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
.
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 GEN
s)
long
evallg(long x)
convert length x
to bitmask (first codeword of all GEN
s). 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.
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
).
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
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.
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)
.
GEN
typeThese 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
.
2
, piThese are double
approximations to useful constants:
@3LOG2
: log 2
.
@3LOG10_2
: log 2 /
log 10
.
@3LOG2_10
: log 10 /
log 2
.
@3M_PI
: pi.
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> */
{
NEXT_PRIME_VIADIFF(p, ptr);
...
}
@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> */
{
NEXT_PRIME_VIADIFF(p, ptr);
...
}
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
.
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_REAL
s 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
GEN
s). 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 GEN
s: 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
.
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).
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 GEN
s 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 GEN
s).
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 GEN
s). 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 GEN
s 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 GEN
s 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 GEN
s, 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
).
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)
.
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
.
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
.
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.
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 GEN
s) 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.
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.
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).
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])
.
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.
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.
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
.
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
.
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_eval
xxx
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
)
D
xxx 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 GEN
s 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 ``D
value,
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
.
gp
as a shared moduleIn 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");
addhelp(ClassGroupInit, "ClassGroupInit(P,{flag=0},{data=[]}):
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!
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.
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
.
@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.
paricfg_datadir
: character string. The location of PARI's datadir
.
\newpage
libPARI - Arithmetic kernel: Level 0 and 1
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)
.
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
.
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
.
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 GEN
s 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).
@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.
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_REAL
s 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.
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 0
s 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.
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_INT
s and t_REAL
s). 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
.
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)
.
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_INT
s, 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 shiftslong
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 GEN
s (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.
t_INT
to bits or digits in base 2^k
and backGEN
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_INT
s, 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 ulong
s, 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.
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_INT
s 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 ulong
s.
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 ulong
s.
long
u_lval(ulong x, ulong p)
as Z_pval
, except the inputs are now ulong
s.
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_INT
s), 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
).
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
.
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_INT
s x
and y
. The result is 1
if x = y
, 0
otherwise.
int
equalrr(GEN x, GEN y)
compares the t_REAL
s 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_INT
s x
and y
. The result is the sign of |x| - |y|
.
int
absequalii(GEN x, GEN y)
compares the t_INT
s x
and y
. The result is 1
if |x |= |y|
, 0
otherwise.
int
abscmprr(GEN x, GEN y)
compares the t_REAL
s 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
.
The operators in this section have arguments of C-type GEN
, long
, and ulong
, and only t_INT
and t_REAL
GEN
s 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_INT
s 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_REAL
s 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_INT
s 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_INT
s 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_REAL
s 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
.
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_INT
s:
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_INT
s:
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).
t_REAL
resultGEN
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
.
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 GEN
s, 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_INT
s 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.
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
.
GEN
powii(GEN x, GEN n)
, assumes x
and n
are t_INT
s 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.
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_INT
s x
and y
.
GEN
lcmii(GEN x, GEN y)
, returns the LCM of the t_INT
s x
and y
.
GEN
bezout(GEN a,GEN b, GEN *u,GEN *v)
, returns the GCD d
of t_INT
s 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]
.
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]
.
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
.
In this subsection, all GEN
s 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_INT
s, 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_INT
s, 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_INT
s 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
.
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
.
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_INT
s.
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_INT
s.
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
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.
A function name is built in the following way: A_1_..._A_n
fun 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/l
Z where l < 2^{BIL}
is not necessarily prime. Implemented using ulong
s
Fp
: Z/p
Z where p
is a t_INT
, not necessarily prime. Implemented as t_INT
s 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 Fp
xxx 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_POL
s 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_INT
s.
Zp
: the p
-adic integers Z_p
, implemented as t_INT
s, for arbitrary p
Zl
: the p
-adic integers Z_p
, implemented as t_INT
s, for p < 2^{BIL}
z
: the integers Z, implemented using (signed) long
s.
Q
: the rational numbers Q, implemented as t_INT
s and t_FRAC
s.
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/p
Z[X]
Y
: polynomial in Y != X
. This is used to resolve ambiguities. E.g. FpXY
means ((
Z/p
Z)[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/p
Z)[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/p
Z)[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_VECSMALL
s, which coefficient understood as ulong
s.
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_VECSMALL
s. This is known as a 'MATSMALL'.
v
and c
are regular t_VECSMALL
s. 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
@3These routines implement univariate polynomial arithmetic and linear algebra over finite fields, in fact over finite rings of the form (
Z/p
Z)[X]/(T)
, where p
is not necessarily prime and T\in(
Z/p
Z)[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/p
Z.
int
Rg_is_Fp(GEN z, GEN *p)
, checks if z
can be mapped to Z/p
Z: 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/p
Z: 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);
z = Fp_add(x, y, p);
return Fp_to_mod(z);
}
else return gadd(x, y);
}
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
.
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 ZM
s 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 ZM
s 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 ZM
s 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 notasymptotically 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 algebraAn 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_INT
s and ZX
s 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 FpX
s. All operations are understood to take place in (
Z/p
Z)[X]
.
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 FpX
s).
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 FpX
s).
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)
.
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
).
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 INT
s, 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_INT
s, 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/p
Z of the FpX
f
. Assumes that p
is prime.
GEN
FpX_oneroot(GEN f, GEN p)
returns one root in Z/p
Z 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/p
Z of the FpX
f
(without multiplicity, as a vector of Fp
s). 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_INT
s (say in variable X
), b
a t_POL
(say in variable X
) whose coefficients are either t_POL
s in Z[Y]
or t_INT
s. 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/p
Z)[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 FpXQ
s by definition, not the other way round.)
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
.
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_INT
s.
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 ZX
s or t_INT
s, reduce them to Fq
s. (If T = NULL
, as FpXX_red(x, p)
.)
GEN
FqV_red(GEN x, GEN T, GEN p)
, x
a vector of ZX
s or t_INT
s, reduce them to Fq
s. (If T = NULL
, only reduce components mod p
to FpX
s or Fp
s.)
GEN
FpXQ_red(GEN x, GEN T,GEN p)
x
a t_POL
whose coefficients are t_INT
s, reduce them to FpXQ
s.
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 T
be 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 Fq
s, 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 FpXQ
s.
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),b
sigma(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 FpXQ
s.
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),b
sigma(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_INT
s or FpX
s. 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 ZX
s or t_INT
s. 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 Fq
s. 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.)
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 ZX
s or t_INT
s, reduce them to FpXQ
s.
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
.
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
.
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 FpXQX
s, returns x*y^{-1}
modulo S
.
GEN
FpXQXQ_inv(GEN x, GEN S, GEN T, GEN p)
, x
and S
being FpXQX
s, 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 FpXQX
s, returns x y
modulo S
.
GEN
FpXQXQ_sqr(GEN x, GEN S, GEN T, GEN p)
, x
and S
being FpXQX
s, returns x^2
modulo S
.
GEN
FpXQXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)
, x
and S
being FpXQX
s, returns x^n
modulo S
.
GEN
FpXQXQ_powers(GEN x, long n, GEN S, GEN T, GEN p)
, x
and S
being FpXQX
s, returns [x^0,..., x^n]
as a t_VEC
of FpXQXQ
s.
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),b
sigma(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 FqX
s, returns x + y
modulo S
.
GEN
FqXQ_sub(GEN x, GEN y, GEN S, GEN T, GEN p)
, x
, y
and S
being FqX
s, returns x - y
modulo S
.
GEN
FqXQ_mul(GEN x, GEN y, GEN S, GEN T, GEN p)
, x
, y
and S
being FqX
s, returns x y
modulo S
.
GEN
FqXQ_div(GEN x, GEN y, GEN S, GEN T, GEN p)
, x
and S
being FqX
s, returns x/y
modulo S
.
GEN
FqXQ_inv(GEN x, GEN S, GEN T, GEN p)
, x
and S
being FqX
s, 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 FqX
s, returns x^2
modulo S
.
GEN
FqXQ_pow(GEN x, GEN n, GEN S, GEN T, GEN p)
, x
and S
being FqX
s, returns x^n
modulo S
.
GEN
FqXQ_powers(GEN x, long n, GEN S, GEN T, GEN p)
, x
and S
being FqX
s, returns [x^0,..., x^n]
as a t_VEC
of FqXQ
s.
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 Fq
s, returns the monic FqX
prod_i (pol_x[v] - V[i])
.
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 FqX
s 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 ZX
s, 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 ZX
s, 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 Flx
s.
@3In the following, an argument called sv
is of the form evalvarn
(v)
for some variable number v
.
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
.
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/p
Z. 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
.
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.
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.
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.
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]
.
t_INTMOD
coefficientsThose functions are mostly needed for interface reasons: t_INTMOD
s 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
.
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_VECSMALL
s) of length n >= 1
, return the vector of t_VEC
s [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_VECSMALL
s) 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 VECSMALL
s (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 MATSMALL
s (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 ulong
s.
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)
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_INT
s, and that 2 amax bmax < m
, attempts to recognize x
as a rational a/b
, i.e. to find t_INT
s 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
.
GEN
Zp_sqrt(GEN b, GEN p, long e)
b
and p
being t_INT
s, 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_INT
s 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_INT
s, 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_INT
s, 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
.
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_INT
s 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_INT
s, 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_INT
s 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^rh
Z_p[X] + p^m
Z_p[X] = f
Z_p[X] + g
Z_p[X] + p^m
Z_p[X].
Return the 0
polynomial if r >= m
and a monic h\in
Z[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
(f
Z_p[X] + g
Z_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.
GEN
ZpXQ_invlift(GEN b, GEN a, GEN T, GEN p, long e)
let p
be a prime t_INT
and a,b
be FpXQ
s (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_INT
s, with n,p > 1
and p
coprime to n
, and a,b
be FpXQ
s (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 p
Z_p[X])
if p
odd or a = 1 (mod 4
Z_2[X])
if p = 2
.
GEN
Zq_sqrtnlift(GEN b, GEN n, GEN a, GEN T, GEN p, long e)
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
.
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
.
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)
p
-adic functionsGEN
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
.
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.
ulong
Rg_to_Fl(GEN z, ulong p)
, z
which can be mapped to Z/p
Z: 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.
GEN
Flx_to_ZX(GEN z)
, converts to ZX
(t_POL
of non-negative t_INT
s 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_INT
s in this case)
GEN
Flv_to_ZV(GEN z)
, converts to ZV
(t_VEC
of non-negative t_INT
s in this case)
GEN
Flm_to_ZM(GEN z)
, converts to ZM
(t_MAT
with non-negative t_INT
s 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)
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 ulong
s.
GEN
nm_Z_mul(GEN y, GEN c)
the entries of y
are ulong
s.
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
.
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.
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.
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_VECSMALL
s. 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)
.
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.
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.
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.
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
.
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
.
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_INT
s.
GEN
primes_interval(GEN a, GEN b)
return the primes in the interval [a,b]
, as a t_VEC
of t_INT
s.
GEN
primes_interval_zv(ulong a, ulong b)
return the primes in the interval [a,b]
, as a t_VECSMALL
of ulongs
s.
GEN
primes_upto_zv(ulong b)
return the primes in the interval [2,b]
, as a t_VECSMALL
of ulongs
s.
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.
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
.
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 ZV
s 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 ulong
s.
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.
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 RgM
s.
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
.
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
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) )
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).
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_VECSMALL
s, *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^e
Z. 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^e
Z, 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
.
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.
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 ZX
s and that T
is monic.
GEN
ZXQ_sqr(GEN x,GEN T)
returns x^2
mod T
, assuming that all inputs are ZX
s and that T
is monic.
GEN
ZXQ_charpoly(GEN A, GEN T, long v)
: let T
and A
be ZX
s, 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 ZX
s.
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_REAL
s. 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 QX
s (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
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_INTMOD
s 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/p
Z, 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)
,
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_POL
s 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
.
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
.
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
.
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_INT
s 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.
GEN
RgX_gcd(GEN x, GEN y)
returns the GCD of x
and y
, assumed to be t_POL
s 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
.
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 RgXn
s.
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 RgXQ
s.
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_POL
s 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 RgX
s (arbitrary GEN
s in fact), reduce them to RgXQ
s (applying grem
coefficientwise) in a t_COL
.
GEN
RgXQV_red(GEN z, GEN T)
z
a t_POL
whose coefficients are RgX
s (arbitrary GEN
s in fact), reduce them to RgXQ
s (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 RgX
s (arbitrary GEN
s in fact), reduce them to RgXQ
s (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
!
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_POLMOD
s 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.
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.
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
).
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
.
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 (*add)(void *E ,GEN, 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)
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)
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.
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.
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)
.
_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\in
Z_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^N
Z_p[X])
,
@3* df_a(w) = b (mod p^M
Z_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
libPARI - Operations on general PARI objects
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.
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
.
GEN
gmodulo(GEN x, GEN y)
creates the object Mod(x,y)
on the PARI stack, where x
and y
are either both t_INT
s, 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 long
s.
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)
.
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_POL
s 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.
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]
.
See also next section for analogs of the following functions:
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.
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_INT
s 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_COL
s of the same length).
GEN
mkmat3(GEN x, GEN y, GEN z)
creates a 3-column t_MAT
with columns x
, y
, z
(t_COL
s 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_COL
s 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_COL
s 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)
.
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
.
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^n
x
, 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)
.
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
.
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 GEN
s.
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.
int
isexactzero(GEN x)
returns 1 (true) if x
is exactly equal to 0 (including t_INTMOD
s 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_INTMOD
s 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.
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.
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)
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.
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)
.
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;
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_POL
s 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_POL
s 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
).
GEN
resultant(GEN x, GEN y)
creates the resultant of the t_POL
s 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.)
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
).
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
.
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 (2i
pi/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)
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.
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|
.
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
libPARI - Miscellaneous mathematical functions
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
.
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
.
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_INT
s. 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.
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_INTMOD
s occurring in the structure, as well as primes p
arising from t_PADIC
s or t_FFELT
s. 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_REAL
s 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
.
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).
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/p
Z. Useful for generic code that wants to handle (inefficiently) Z/p
Z 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)
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)
.
t_REAL
argumentsIn 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
.
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 (2i
pi 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.
t_PADIC
argumentsGEN
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.
The cached constant is returned at its current precision, which may be larger than prec
. One should always use the mp
xxx 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_REAL
s 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^n
pi at precision prec
.
GEN
PiI2(long n, long prec)
returns the complex number 2
pi i
at precision prec
.
GEN
PiI2n(long n, long prec)
returns the complex number 2^n
pi 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.
@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_VECSMALL
s 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.
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
libPARI - Standard data structures
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 GEN
s, 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
.
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
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.
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)
.
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
).
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)
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
.
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.
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.
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.
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
.
s
. pari_err(e_BUG, const char *s)
pari_err_BUG(const char *s)
@3prints the error message
Bug in s, please report
.
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'
.
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
.
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
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
.
s
. pari_err(e_FLAG, const char *s)
pari_err_FLAG(const char *s)
@3prints the error message
invalid flag in s
.
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
.
O(2) + O(3)
it is valid to add two t_PADIC
s, 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
.
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)
.
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.
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
.
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
.
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.
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.
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
.
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.
pari_malloc
or pari_realloc
failed. pari_err(e_MEM)
@3prints the error message
not enough memory
.
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
.
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
.
pari_err(e_STACK)
@3prints the error message
the PARI stack overflows !
as well as some statistics concerning stack usage.
alarm
function. pari_err(e_ALARM, const char *fmt, ...)
@3prints the error message
s
.
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
.
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
.
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
.
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
.
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
.
pari_err(e_MISC, const char *fmt, ...)
@3prints the error message
s
.
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.
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
.
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
.
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
.
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.
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)
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.
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;
}
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;
}
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.
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 **
.
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).
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
.
These functions handle t_VEC
as an abstract container type of GEN
s. 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
.
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.
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
libPARI - Functions related to the GP interpreter
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.
long
loop_break(void)
processes an eventual flow changes inside an iterator. If this function return 1
, the iterator should stop.
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
.
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
GEN
s 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);
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.
Two families of standard wrappers are provided to interface iterators like intnum
or sumnum
with GP.
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).
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.
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).
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 struct
s, 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 struct
s.
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.