cypari2: Python bindings for PARI/GP

Jeroen Demeyer

Universiteit Gent / OpenDreamKit

(joint work with Vincent Delecroix, Luca De Feo, Vincent Klein, …)

Quick examples

In [21]:
from cypari2 import Pari
pari = Pari()
pari.zeta(2)
Out[21]:
1.64493406684823
In [22]:
pari.ellinit([-112, 400]).ellanalyticrank()
Out[22]:
[3, 10.3910994007158]
In [23]:
pari.polmodular(3)
Out[23]:
x^4 + (-y^3 + 2232*y^2 - 1069956*y + 36864000)*x^3 + (2232*y^3 + 2587918086*y^2 + 8900222976000*y + 452984832000000)*x^2 + (-1069956*y^3 + 8900222976000*y^2 - 770845966336000000*y + 1855425871872000000000)*x + (y^4 + 36864000*y^3 + 452984832000000*y^2 + 1855425871872000000000*y)

Plotting (using SVG images)

In [24]:
pari("my(Z=lfuninit(1, [100])); ploth(x=0, 100, lfunhardy(Z,x))")
7.8031-7.26630100
Out[24]:
[0.E-307, 100.000000000000, -7.26626527057968, 7.80311802062338]

Python interaction

In [25]:
discs = set(pari.quaddisc(-1-n) for n in range(200))
sorted([D for D in discs if D.qfbclassno() == 1], reverse=True)
Out[25]:
[-3, -4, -7, -8, -11, -19, -43, -67, -163]
In [26]:
def cube(x):
    return x**3

pari.apply(cube, range(10))
Out[26]:
[0, 1, 8, 27, 64, 125, 216, 343, 512, 729]

Errors

In [27]:
1 / pari.Mod(4, 6)
---------------------------------------------------------------------------
PariError                                 Traceback (most recent call last)
<ipython-input-27-817f380fe1ec> in <module>()
----> 1 1 / pari.Mod(4, 6)

cypari2/gen.pyx in cypari2.gen.Gen.__div__()

cypari2/handle_error.pyx in cypari2.handle_error._pari_err_handle()

PariError: impossible inverse in Fp_inv: Mod(2, 6)

Implementation

cypari2 is written in Cython, a Python-like language compiling to C (like gp2c but for Python)

PARI objects (GEN) are wrapped in a Python object Gen (independent of the PARI type):

In [28]:
x = pari.pi()
print(type(x))
print(x.type())
<type 'cypari2.gen.Gen'>
t_REAL

Auto-generation

Cython code wrapping most GP functions is auto-generated from pari.desc. Example:

Function: cos
Class: basic
Section: transcendental
C-Name: gcos
Prototype: Gp
Help: cos(x): cosine of x.
Doc: cosine of $x$.

This becomes

def cos(self, x, long precision=0):
        r'''
        Cosine of :math:`x`.
        '''
        x = objtogen(x)
        sig_on()
        cdef GEN _x = (<Gen>x).g
        precision = prec_bits_to_words(precision)
        cdef GEN _ret = gcos(_x, precision)
        return new_gen(_ret)

Performance

cypari2 is very fast:

  • Cython allows direct C calls to the PARI library
  • Objects remain on the PARI stack if possible, no needless copying (several unsafe operations require cloning anyway: resizing PARI stack, getting/setting entry of vector/matrix)

Only overhead comes from dealing with Python objects and methods

In [29]:
pari.allocatemem(2**28)
def hilberttrace(n):
    m = pari.mathilbert(n)
    m.trace()
PARI stack size set to 268435456 bytes, maximum size set to 268435456
In [30]:
%time hilberttrace(1000)
CPU times: user 5 ms, sys: 13 ms, total: 18 ms
Wall time: 18.7 ms
In [31]:
%%script gp -q
hilberttrace(n) = {my(m=mathilbert(n)); trace(m); return;}
hilberttrace(1000);
time = 61 ms.

History (a.k.a. why is it called cypari2?)

  • ≤ 2006: Very early versions of SageMath using Pyrex/Cython wrappers of PARI
  • 2012: Marc Culler and Nathan Dunfield forked these into a separate Python package cypari (to use it with their SnapPy topology package)
  • 2015: auto-generation of wrappers in SageMath
  • 2016: these were made into a separate package cypari2
  • 2018: cypari2 version 2 released, keeping GENs on the PARI stack instead of always copying
  • cypari and cypari2 are still separate packages because of build/packaging issues and Windows compatibility of cysignals

TODO

  • better support for functions
  • support iterators (problem: PARI/GP iterators are not easily usable from C)
  • support attributes like .clgp (problem: omega() versus .omega incompatibility)
  • slicing (M[,1] for a matrix M)

Try it!

Assuming Python ≥ 2.7 and PARI/GP version ≥ 2.9.4 (installed in a location where Python will find it):

pip install cypari2

...or use SageMath.

Sources: https://github.com/sagemath/cypari2

In [ ]: