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 Python int or long.

INPUT:

  • x – a PARI t_INT, t_FRAC, t_REAL, a purely real t_COMPLEX, a t_INTMOD or t_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 (type t_FRAC)

  • a float for real numbers (type t_REAL)

  • a complex for complex numbers (type t_COMPLEX)

  • a list for vectors (type t_VEC or t_COL). The function gen_to_python is then recursively applied on the entries.

  • a list of Python integers for small vectors (type t_VECSMALL)

  • a list of list``s for matrices (type ``t_MAT). The function gen_to_python is then recursively applied on the entries.

  • the floating point inf or -inf for infinities (type t_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 or long to a PARI gen of type t_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)