Convert PARI objects to/from Python/C native types¶
This modules contains the following conversion routines:
integers, long integers <-> PARI integers
list of integers -> PARI polynomials
doubles -> PARI reals
pairs of doubles -> PARI complex numbers
PARI integers are stored as an array of limbs of type pari_ulong
(which are 32-bit or 64-bit integers). Depending on the kernel
(GMP or native), this array is stored little-endian or big-endian.
This is encapsulated in macros like int_W()
:
see section 4.5.1 of the
PARI library manual.
Python integers of type int
are just C longs. Python integers of
type long
are stored as a little-endian array of type digit
with 15 or 30 bits used per digit. The internal format of a long
is
not documented, but there is some information in
longintrepr.h.
Because of this difference in bit lengths, converting integers involves some bit shuffling.
- cypari2.convert.gen_to_integer(x)¶
Convert a PARI
gen
to a Pythonint
orlong
.INPUT:
x
– a PARIt_INT
,t_FRAC
,t_REAL
, a purely realt_COMPLEX
, at_INTMOD
ort_PADIC
(which are lifted).
Examples:
>>> from cypari2.convert import gen_to_integer >>> from cypari2 import Pari >>> pari = Pari() >>> a = gen_to_integer(pari("12345")); a; type(a) 12345 <... 'int'> >>> gen_to_integer(pari("10^30")) == 10**30 True >>> gen_to_integer(pari("19/5")) 3 >>> gen_to_integer(pari("1 + 0.0*I")) 1 >>> gen_to_integer(pari("3/2 + 0.0*I")) 1 >>> gen_to_integer(pari("Mod(-1, 11)")) 10 >>> gen_to_integer(pari("5 + O(5^10)")) 5 >>> gen_to_integer(pari("Pol(42)")) 42 >>> gen_to_integer(pari("u")) Traceback (most recent call last): ... TypeError: unable to convert PARI object u of type t_POL to an integer >>> s = pari("x + O(x^2)") >>> s x + O(x^2) >>> gen_to_integer(s) Traceback (most recent call last): ... TypeError: unable to convert PARI object x + O(x^2) of type t_SER to an integer >>> gen_to_integer(pari("1 + I")) Traceback (most recent call last): ... TypeError: unable to convert PARI object 1 + I of type t_COMPLEX to an integer
Tests:
>>> gen_to_integer(pari("1.0 - 2^64")) == -18446744073709551615 True >>> gen_to_integer(pari("1 - 2^64")) == -18446744073709551615 True >>> import sys >>> if sys.version_info.major == 3: ... long = int >>> for i in range(10000): ... x = 3**i ... if long(pari(x)) != long(x) or int(pari(x)) != x: ... print(x)
Check some corner cases:
>>> for s in [1, -1]: ... for a in [1, 2**31, 2**32, 2**63, 2**64]: ... for b in [-1, 0, 1]: ... Nstr = str(s * (a + b)) ... N1 = gen_to_integer(pari(Nstr)) # Convert via PARI ... N2 = int(Nstr) # Convert via Python ... if N1 != N2: ... print(Nstr, N1, N2) ... if type(N1) is not type(N2): ... print(N1, type(N1), N2, type(N2))
- cypari2.convert.gen_to_python(z)¶
Convert the PARI element
z
to a Python object.OUTPUT:
a Python integer for integers (type
t_INT
)a
Fraction
(fractions
module) for rationals (typet_FRAC
)a
float
for real numbers (typet_REAL
)a
complex
for complex numbers (typet_COMPLEX
)a
list
for vectors (typet_VEC
ort_COL
). The functiongen_to_python
is then recursively applied on the entries.a
list
of Python integers for small vectors (typet_VECSMALL
)a
list
oflist``s for matrices (type ``t_MAT
). The functiongen_to_python
is then recursively applied on the entries.the floating point
inf
or-inf
for infinities (typet_INFINITY
)a string for strings (type
t_STR
)other PARI types are not supported and the function will raise a
NotImplementedError
Examples:
>>> from cypari2 import Pari >>> from cypari2.convert import gen_to_python >>> pari = Pari()
Converting integers:
>>> z = pari('42'); z 42 >>> a = gen_to_python(z); a 42 >>> type(a) <... 'int'>
>>> gen_to_python(pari('3^50')) == 3**50 True >>> type(gen_to_python(pari('3^50'))) == type(3**50) True
Converting rational numbers:
>>> z = pari('2/3'); z 2/3 >>> a = gen_to_python(z); a Fraction(2, 3) >>> type(a) <class 'fractions.Fraction'>
Converting real numbers (and infinities):
>>> z = pari('1.2'); z 1.20000000000000 >>> a = gen_to_python(z); a 1.2 >>> type(a) <... 'float'>
>>> z = pari('oo'); z +oo >>> a = gen_to_python(z); a inf >>> type(a) <... 'float'>
>>> z = pari('-oo'); z -oo >>> a = gen_to_python(z); a -inf >>> type(a) <... 'float'>
Converting complex numbers:
>>> z = pari('1 + I'); z 1 + I >>> a = gen_to_python(z); a (1+1j) >>> type(a) <... 'complex'>
>>> z = pari('2.1 + 3.03*I'); z 2.10000000000000 + 3.03000000000000*I >>> a = gen_to_python(z); a (2.1+3.03j)
Converting vectors:
>>> z1 = pari('Vecsmall([1,2,3])'); z1 Vecsmall([1, 2, 3]) >>> z2 = pari('[1, 3.4, [-5, 2], oo]'); z2 [1, 3.40000000000000, [-5, 2], +oo] >>> z3 = pari('[1, 5.2]~'); z3 [1, 5.20000000000000]~ >>> z1.type(), z2.type(), z3.type() ('t_VECSMALL', 't_VEC', 't_COL')
>>> a1 = gen_to_python(z1); a1 [1, 2, 3] >>> type(a1) <... 'list'> >>> [type(x) for x in a1] [<... 'int'>, <... 'int'>, <... 'int'>]
>>> a2 = gen_to_python(z2); a2 [1, 3.4, [-5, 2], inf] >>> type(a2) <... 'list'> >>> [type(x) for x in a2] [<... 'int'>, <... 'float'>, <... 'list'>, <... 'float'>]
>>> a3 = gen_to_python(z3); a3 [1, 5.2] >>> type(a3) <... 'list'> >>> [type(x) for x in a3] [<... 'int'>, <... 'float'>]
Converting matrices:
>>> z = pari('[1,2;3,4]') >>> gen_to_python(z) [[1, 2], [3, 4]]
>>> z = pari('[[1, 3], [[2]]; 3, [4, [5, 6]]]') >>> gen_to_python(z) [[[1, 3], [[2]]], [3, [4, [5, 6]]]]
Converting strings:
>>> z = pari('"Hello"') >>> a = gen_to_python(z); a 'Hello' >>> type(a) <... 'str'>
Some currently unsupported types:
>>> z = pari('x') >>> z.type() 't_POL' >>> gen_to_python(z) Traceback (most recent call last): ... NotImplementedError: conversion not implemented for t_POL
>>> z = pari('12 + O(2^13)') >>> z.type() 't_PADIC' >>> gen_to_python(z) Traceback (most recent call last): ... NotImplementedError: conversion not implemented for t_PADIC
- cypari2.convert.integer_to_gen(x)¶
Convert a Python
int
orlong
to a PARIgen
of typet_INT
.Examples:
>>> from cypari2.convert import integer_to_gen >>> from cypari2 import Pari >>> pari = Pari() >>> a = integer_to_gen(int(12345)); a; type(a) 12345 <... 'cypari2.gen.Gen'> >>> integer_to_gen(float(12345)) Traceback (most recent call last): ... TypeError: integer_to_gen() needs an int or long argument, not float >>> integer_to_gen(2**100) 1267650600228229401496703205376
Tests:
>>> import sys >>> if sys.version_info.major == 3: ... long = int >>> assert integer_to_gen(long(12345)) == 12345 >>> for i in range(10000): ... x = 3**i ... if pari(long(x)) != pari(x) or pari(int(x)) != pari(x): ... print(x)