GEN
sgp
as a shared moduleinstall
gp
2
-adic valuations and shiftst_REAL
resultFpC
/ FpV
, FpM
Fp
-linear algebra The implementations are notFqC
, FqM
and Fq
-linear algebraFlc
/ Flv
, Flm
F2c
/ F2v
, F2m
FlxqV
, FlxqM
Zlm
FpX
p
is always a t_INT
,p
is always a t_INT
,FpXQ
, Fq
FpXQ
Fq
FpXX
, FpXY
FpXQX
, FqX
Flx
FlxV
FlxT
Flxq
FlxX
FlxqX
FlxqXQ
F2x
F2xq
F2xqV
, F2xqM
.t_INTMOD
coefficientsp
-adic functionsZC
/ ZV
, ZM
zv
, zm
ZMV
/ zmV
(vectors of ZM
/zm
)RgC
/ RgV
, RgM
t_FFELT
t_REAL
argumentst_PADIC
argumentss
is not available on thiss
.s
is not implemented.s
.s
have inconsistents
.o
in function s
containsx
of function s
had an unexpected type.x
and y
submitted to function s
havex
is not in the function's domain (as inpari_malloc
or pari_realloc
failed.s
becomes too large to bes
fails because input accuracy is too low.alarm
function.error
(g_1,...,g_n)
s
is a constant polynomial,s
expected two coprime arguments, and didx
.s
expected an irreducible polynomial,x
and y
submitted to function s
ares
expected a prime number, and did receive p
,s
is a zero polynomial, andn
-th root of x
, which does nott_CLOSURE
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
initprimetable
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.
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.
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_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)
fork a PARI daemon, detaching from the main
process group. The function returns 1 in the parent, and 0 in the
forked son.
An entree
is the generic object associated 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
: an integer from 1 to 11 (to which group of function
help do we belong).
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: general functions
(functions_basic
, known to libpari
), gp-specific functions
(functions_gp
), gp-specific highlevel functions
(functions_highlevel
), and 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);
void
pari_add_oldmodule(entree *mod)
adds all the routines in module
mod
to the table of symbols in the interpreter when running in
``PARI 1.xx compatible'' mode (see default(compatible)
) . It assumes
that
pari_init
has been called.
A GP default
is likewise associated to a helper routine, that is run
when the value is consulted, or changed by default0
or setdefault
.
Such routines are grouped into modules: functions_default
containing all
defaults that make sense in libpari context, functions_gp_rl_default
containing defaults that are gp
-specific and do not make sense unless
we use libreadline
, and functions_gp_default
containing all other
gp
-specific defaults.
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_handle_exception}{extern 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.
\doc{cb_pari_sigint}{void (*cb_pari_sigint)(void)}.
Function called when we receive SIGINT
. By default, raises
pari_err(e_MISC, "user interrupt");
\doc{cb_pari_pre_recover}{extern 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}{extern 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.
@3Utility function.
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);
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
prec2ndec(long x)
converts a number of 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
nbits2prec(long x)
converts a number of bits to a number of
codewords. This is equal to 2 + 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
bit_accuracy(long x)
converts a t_REAL
length into a number
of significant bits. Returns (x - 2)BIL
.
double
bit_accuracy_mul(long x, double y)
returns (x - 2)BIL x y
.
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
.
Raise a type error if typ(x)
is not among those three.
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 belongs to
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_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_term(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_term(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
.
@3PI
: 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 will just
print the error message:
*** not enough precomputed primes, need primelimit ~ c
@3(for some numerical value c
), then abort 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
.
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.
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.
void
pari_var_create(entree *ep)
low-level initialization of an
EpVAR
.
@3The obsolete function long
manage_var(long n, entree *ep)
is kept for backward compatibility only. Don't use it.
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.
entree*
fetch_named_var(char *s)
as fetch_user_var
, but
returns an entree*
suitable for inclusion in the interpreter hashlists
of symbols, not a variable number. fetch_user_var
is a trivial
wrapper.
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*
associated
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: use fetch_named_var
to get a user variable of
the right name in the first place.
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
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
)
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
p
real precision (default realprecision
)
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 (see Label se:strings), 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 &
.
Dr
optional raw string, send NULL
if argument omitted.
Ds
optional char *
, send NULL
if argument omitted.
DV
optional *entree
, send NULL
if argument omitted.
DI
, DE
optional closure, send NULL
if argument omitted.
Dn
optional variable number, -1
if 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
associated 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")
@3(see Label se:addhelp and se:install). The 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 (Label se: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
associated 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_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_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
.
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_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
.
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_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( -bit_accuracy(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
. 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.
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 succeed.
int
is_bigint_lg(GEN n, long l)
true if itos(n)
would succeed.
Assumes lgefint(n)
is equal to l
.
ulong
itou(GEN x)
converts the t_INT
|x|
to an ulong
if
possible, otherwise raise an exception.
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.
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
equalui(ulong s, GEN x)
int
equaliu(GEN x, ulong s)
compare the absolute value of the
t_INT
x
and the ulong
s
. The result is 1
if
|x |= y
, 0
otherwise.
int
cmpui(ulong u, GEN x)
int
cmpiu(GEN x, ulong u)
compare the absolute value of the
t_INT
x
and the ulong
s
.
int
absi_cmp(GEN x, GEN y)
compares the t_INT
s x
and y
.
The result is the sign of |x| - |y|
.
int
absi_equal(GEN x, GEN y)
compares the t_INT
s x
and y
. The result is 1
if |x |= |y|
, 0
otherwise.
int
absr_cmp(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
. Very inefficient when a = 0
.
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.
GEN
divsi_rem(long s, GEN y, long *r)
computes the Euclidean quotient
and remainder of the t_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 t_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
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
.
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
powruvec(GEN e, ulong n)
. Given a t_REAL
e
, return the vector
of all e^i
, 1 <= i <= n
.
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 belongs to {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
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_gcdext(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]
.
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_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_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)
.
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 currently
undefined.
GEN
Fp_order(GEN a, GEN N, GEN p)
returns the order of the
Fp
a
. If N
is non-NULL
, it is assumed that N
is a multiple of the order of a
, as a t_INT
or a
factorization matrix.
GEN
Fp_factored_order(GEN a, GEN N, 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
. If N
is non-NULL
, it is assumed that
N
is a multiple of the order of a
, as a t_INT
or a
factorization matrix.
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 x, GEN n, GEN p, GEN *zn)
returns an n
-th
root of x
modulo p
(smallest non-negative residue), where
x
, n
, p
are t_INT
s, and p
is assumed to be prime.
Return NULL
if x
is not an n
-th power residue. Otherwise,
if zn
is non-NULL
set it to a primitive n
-th root of 1
.
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
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
.
ulong
coreu(ulong n)
, unique squarefree integer d
dividing n
such
that n/d
is a square.
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.
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
is x
is a fundamental
discriminant, and 0
otherwise.
long
unegisfundamental(ulong x)
return 1
is -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
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 associated 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.
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.
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 belongs to (
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)
.
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
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
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
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.
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 the inverse of x
, or
NULL
if x
is not invertible.
GEN
FpM_FpC_invimage(GEN m, GEN v, GEN p)
given an FpM
x
and an FpC
y
, returns an x
such that Ax =
y
, or NULL
if no such vector exist.
GEN
FpM_invimage(GEN m, GEN v, GEN p)
given two FpM
x
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_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
Flc_Fl_mul(GEN x, ulong y, ulong p)
multiplies the Flv
x
by y
.
void
Flc_Fl_mul_inplace(GEN x, ulong y, ulong p)
replaces
the Flc
x
by x*y
.
void
Flc_Fl_mul_part_inplace(GEN x, ulong y, ulong p, long l)
multiplies x[1..l]
by y
modulo p
. In place.
GEN
Flc_Fl_div(GEN x, ulong y, ulong p)
divides the Flv
x
by y
.
void
Flc_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_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_sum(GEN x, ulong p)
returns the sums of the components of x
.
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
row_Flm(GEN A, long x0)
return A[i,]
, the i
-th row of the
Flm
(or zm
) A
.
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
x
and an Flc
y
, returns an x
such that Ax = y
, or NULL
if no such vector exist.
GEN
Flm_invimage(GEN x, GEN y, ulong p)
given two Flm
x
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_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
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
F2c_to_Flc(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)
Zlm
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.
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_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_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_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)
.
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
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)
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
.
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).
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_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
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
).
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
, 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 FpXQ
obtained by applying Rg_to_FpXQ
coefficientwise and simplifying scalars to t_INT
s.
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
FpXQX_renormalize(GEN x, long lx)
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
.
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 currently 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
. If o
is non-NULL
, it is assumed that o
is a multiple of the order of a
, either as a t_INT
or a
factorization matrix. Assumes 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)
returns an
n
-th root of x
. Return NULL
if x
is not an
n
-th power residue. Otherwise, if zn
is non-NULL
set it to
a primitive n
-th root of the unity. Assumes that T
is irreducible
mod p
.
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_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
.
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
. 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 x, GEN n, GEN T, GEN p, GEN *zn)
returns an
n
-th root of x
. Return NULL
if x
is not an
n
-th power residue. Otherwise, if zn
is non-NULL
set it to
a primitive n
-th root of the unity. Assumes that T
is irreducible
mod p
.
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
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)
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
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)
.
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
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 x, GEN Y, ulong p)
Q
an FpXY
and
y
being an FpXQ
, returns the FpXQX
Q(x,Y)
, where Y
is the
first variable of Q
.
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
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_divrem(GEN x, GEN y, GEN T, GEN p, GEN *z)
GEN
FqX_div(GEN x, GEN y, GEN T, GEN p)
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_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
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) belongs to
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 belongs to
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_rem(GEN x, GEN y, 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
FpXQX_rem_Barrett(GEN x, GEN iy, GEN y, GEN T, GEN p)
returns x
mod y
, assuming iy
is the Barrett inverse of y
.
GEN
FpXQX_divrem_Barrett(GEN x, GEN iy, GEN y, GEN T, GEN p, GEN *pr)
performs the Euclidean division of x
by y
, assuming iy
is the Barrett
inverse of y
. Returns the quotient and set *pr
to the remainder.
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_FpXQXQ_eval(GEN f,GEN x,GEN S, GEN T,GEN p)
returns
f(x)
.
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
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
FqX_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_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
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 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_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_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_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_pow(GEN x, long n, ulong p)
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.
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_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_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
Flx_normalize(GEN z, ulong p)
, as FpX_normalize
.
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
.
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
.
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_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
.
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 Flxq_autsum
.
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
.
GEN
Flxq_order(GEN a, GEN ord, GEN T, ulong p)
returns the order of the t_Flxq
a
.
If o
is non-NULL
, it is assumed that o
is a multiple of the
order of a
, either as a t_INT
or a factorization matrix.
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_log(GEN a, GEN g, GEN ord, GEN T, ulong p)
Let g
of exact
order ord
in the field F_p[X]/(T)
. Return e
such that a^e = g
. If
e
does not exists, the result is currently undefined. Assumes that T
is irreducible mod p
.
GEN
Flxq_sqrtn(GEN x, GEN n, GEN T, ulong p, GEN *zn)
returns an
n
-th root of x
. Return NULL
if x
is not an
n
-th power residue. Otherwise, if zn
is non-NULL
set it to
a primitive n
-th root of 1
. Assumes that T
is irreducible mod
p
.
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
.
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
FlxY_evalx(GEN x, ulong y, ulong p)
GEN
FlxY_Flxq_evalx(GEN x, GEN y, ulong p)
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.
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) belongs to
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 belongs to
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_pow(GEN x, long 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_rem_Barrett(GEN x, GEN mg, 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
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
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_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
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
ZXX_to_F2xX(GEN x, long v)
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
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)
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_sqrt(GEN x)
returns the squareroot of x
, assuming x
is a
square of a F2x
.
GEN
F2x_factor(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)
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.
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_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
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_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
rootpadicfast(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
. This is a very important
special case of rootpadic
.
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
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 we find
a root 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
ZpX_liftfact(GEN A, GEN B, GEN T, GEN p, long e, GEN pe)
is
the routine underlying polhensellift
. Here, p
is prime, T(Y)
defines a finite field F_q
, either F_q =
F_p
(T
is NULL
)
or a non-prime finite field (T
an FpX
). A
is a polynomial in
Z[X]
(T
NULL
) or Z[X,Y]
, whose leading coefficient
is non-zero in F_q
. B
is a vector of monic FpX
(T
NULL
) 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)
.
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.
p
-adic functionslong
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 belongs to
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 belongs to
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
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
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
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
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
.
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
ZXXV_to_FlxXV(GEN V, ulong p, long v)
, as ZXX_to_FlxX
,
repeatedly called on the vector's coefficients.
GEN
RgC_to_Flc(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
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
coefficients are 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
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
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 v)
converts a t_INT
to a scalar
polynomial in variable 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
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
absi_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
E<lt> 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
absi_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)
.
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.
In the following two 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 associated 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 associated 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 associated to the factorization of an integer, and return NULL
(plain t_INT
) or a factorization extracted from n
otherwise.
Routines associated 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
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 is 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
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
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_gcdext(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_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_multosym(GEN x, GEN y)
GEN
ZM_transmultosym(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_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
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
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 is the ZM
x
is the
identity matrix, and 0 otherwise.
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
.
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
row_zm(GEN A, long x0)
as row_Flm
.
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)
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_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_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
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
gram_matrix(GEN v)
returns the Gram matrix (v_i.v_j)
associated 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 is the t_MAT
x
is the
identity matrix, and 0 otherwise.
int
RgM_isdiagonal(GEN x)
return 1 is the t_MAT
x
is a
diagonal matrix, and 0 otherwise.
int
RgM_is_ZM(GEN x)
return 1 is 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 - x{Id}
, where M
is an n x n
square matrix.
Returns the Frobenius form of M
. Used by matfrobenius
.
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.
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_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 belongs to
Z[X]
has possibly
smaller coefficients.
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_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_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
.
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) belongs to
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) belongs to
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 belongs to
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_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^{2n-1})
and Q(X,X^{2n-1}
of P
and Q
. 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_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. 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)
,
int
RgX_isscalar(GEN x)
return 1 if x
all the coefficients of
x
of degree > 0
are 0
(as per gequal0
).
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)]
. This is a 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
.
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)]
. This is a shallow function.
GEN
RgX_copy(GEN x)
returns (a deep copy of) x
.
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_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_mullow(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
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_sqrlow(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
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
.
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
.
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_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_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_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_modXn_shallow(GEN x, long n)
return x % t^n
,
where n >= 0
. Shallow function.
GEN
RgX_modXn_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 belongs to R[t]
.
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_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_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_max(GEN P, long *d)
sets d
to the largest exponent
such that P
is of the form P(x^d)
(use gequal0
to check
whether coefficients are 0), 0
if P
is the zero polynomial. Returns
RgX_deflate(P,d)
.
GEN
RgX_inflate(GEN P, long d)
return P(X^d)
. Shallow function, not
suitable for gerepileupto
.
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
.
int
RgX_is_rational(GEN P)
return 1 is the RgX
P
has only
rational coefficients (t_INT
and t_FRAC
), and 0 otherwise.
int
RgX_is_QX(GEN P)
return 1 is the RgX
P
has only
t_INT
and t_FRAC
coefficients, and 0 otherwise.
int
RgX_is_ZX(GEN P)
return 1 is 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
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.
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}S< >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
.
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
.
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
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
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
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
Kronecker_to_mod(GEN z, GEN T)
z belongs to 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) belongs to 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
!
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
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)
\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 x
is a non-zero t_REAL
,
returns an approximation to log2(|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
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_RgV(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_RgV(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.
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 x
is non-zero.
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_x_powers(long N, long v)
returns the powers of
pol_x(v)
, of degree 0
to N
, in a vector with N+1
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.
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
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
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
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
words
(unsigned long
). It is assumed that all such arguments are less than
2^{32}
(the actual sizeof(long)
is irrelevant, the behavior is also
as above on 64
-bit machines).
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]
.
Calls divide_conquer_prod
, so 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)
. Calls
divide_conquer_prod
.
Calls divide_conquer_prod
, so 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
.
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
E<lt> 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
. Zero exponents in
the latter factorization are preserved, e.g. when merging the factorization
of 2
and 1/2
, the result is 2^0
.
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_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
.
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
.
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
. 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 t_INT
,
as diviiround
. 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
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(GEN s, GEN x)
GEN
gmul(GEN x, GEN y)
, GEN
gmulgs(GEN x, long s)
,
GEN
gmulsg(GEN s, GEN x)
GEN
gsub(GEN x, GEN y)
, GEN
gsubgs(GEN x, long s)
,
GEN
gsubsg(GEN s, GEN x)
GEN
gdiv(GEN x, GEN y)
, GEN
gdivgs(GEN x, long s)
,
GEN
gdivsg(GEN 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
* 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)
.
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)
GEN
divide_conquer_prod(GEN v, GEN (*mul)(GEN,GEN))
v
is a vector of
objects, which can be ``multiplied'' using the mul
function. Return
the ``product'' of the v[i]
using a product tree: by convention
return gen_1
if v
is the empty vector, a copy of v[1]
if it has a
single entry; and otherwise apply the function recursively on the vector
(twice smaller)
mul
(v[1],v[2])
, mul
(v[3],v[4])
,...
@3Only requires that mul
is an associative binary operator,
which need not correspond to a true multiplication. D
is meant to encode
an arbitrary evaluation context, set it to NULL
in simple cases where you
do not need this. Leaves some garbage on stack, but suitable for
gerepileupto
if mul
is.
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
divide_conquer_assoc(GEN v, void *D, F2 op)
general version of divide_conquer_prod
. 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
.
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
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)
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_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
RgX_RgM_eval_col(GEN q, GEN x, long c)
evaluates the t_POL
q
at the square matrix x
but only returns the c
-th column of the result.
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
associated 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
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
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
.
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
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
.
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 cardinal 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
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)
, int
FF_equal1(GEN a)
,
int
FF_equalm1(GEN a)
returns 1
if the t_FFELT
a
is equal
to 0
(resp. 1
, resp. -1
) else 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
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
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
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
exp1r_abs(GEN x)
returns exp (|x|) - 1
, assuming x != 0
.
GEN
logr_abs(GEN x)
returns log (|x|)
, assuming x != 0
.
@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.
@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 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 belongs to S_n
being
given as a product of disjoint cycles, return the orbits of the subgroup
generated by p
on {1,2,...,n}
.
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 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 permutation 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
the 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 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 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 associated 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_unquoted(GEN x)
as GENtostr
with the following
differences: 1) a t_STR
x
is printed without enclosing quotes
(to be used by print
); 2) the result is allocated on the stack
and must not be freed.
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, associated to the colors
default. The following symbolic
names are associated 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 associated 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 associated 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 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 belongs to {+, *, /, %, = }
, 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, GEN x) pari_err_INV(GEN x)
@3prints the error message
impossible inverse: 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 -1em
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
.
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.
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_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 associated to k
and v
is not reclaimed.
void
hash_destroy(hashtable *h)
deletes the hashtable, by removing all
entries.
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 concat1
.
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
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
E<lt>= 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
E<lt>= i_2
.
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
.
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
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_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.
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_callgen1(GEN C, GEN x)
evaluate the t_CLOSURE
C
with argument x
. Assumes C
has arity >= 1
.
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'
.
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
.
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.
int
pari_is_default(const char *s)
return 1
if s
is the name
of a default, 0
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_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_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_histsize(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_path(const char *v, long flag)
GEN
sd_prettyprinter(const char *v, long flag)
GEN
sd_primelimit(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(char *v, int flag)
GEN
sd_strictargs(const char *v, long flag)
GEN
sd_strictmatch(const char *v, long flag)
GEN
sd_threadsize(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 associated to the value i
of the default. The last entry in the
msg
array is used as a message associated 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 associated 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_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_prec(GEN S, long tag, GEN (*build)(GEN,long), long
prec)
if the tag-component of S
is non empty and has
gprecision
>= 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.