The pyadic library is Python 3 package that provides number types for finite fields ModP) and PAdic). The goal is to mimic the flexible behavior of built-in types, such as int, float and complex. Thus, one can mix-and-match the different number types, as long as the operations are consistent. In particular, ModP and PAdic are compatible with fractions.Fraction.
In addition to arithmetic operations, the pyadic library also provides the following functions:
-
rationaliseto perform rationalization ($\mathbb{F}_p\rightarrow \mathbb{Q}$ and$\mathbb{Q}_p \rightarrow \mathbb{Q}$ ); -
finite_field_sqrtandpadic_sqrtto compute square roots (which may involveFieldExtension); -
padic_logto compute the$p$ -adic logarithm. - polynomial and rational function interpolation, see
interpolation.pymodule.
A shout-out to galois for a very nice tool. It is recommented for vectorized finite field operations, unless type compatibility is an issue. For scalar operation this repo is recommended. See performance comparison below.
The package is available on the Python Package Index
pip install pyadicAlternativelty, it can be installed by cloning the repo
git clone https://github.com/GDeLaurentis/pyadic.git path/to/repo
pip install -e path/to/repopip will automatically install the required packages, which are
numpy, sympy
Additionally, pytest is needed for testing.
Extensive tests are implemented with pytest
pytest --cov pyadic/ --cov-report html tests/ --verboseIn [1]: from pyadic import PAdic, ModP
In [2]: from fractions import Fraction as Q
# 7/13 as a 12-digit 2147483647-adic number
In [3]: PAdic(Q(7, 13), 2147483647, 12)
Out [3]: 1817101548 + 825955248*2147483647 + 1156337348*2147483647^2 + 330382099*2147483647^3 + 1321528398*2147483647^4 + 991146298*2147483647^5 + 1817101547*2147483647^6 + 825955248*2147483647^7 + 1156337348*2147483647^8 + 330382099*2147483647^9 + 1321528398*2147483647^10 + 991146298*2147483647^11 + O(2147483647^12)
# 7/13 in F_2147483647
In [4]: ModP(Q(7, 13), 2147483647)
Out [4]: 1817101548 % 2147483647
# Mapping back to rational numbers
In [5]: from pyadic.finite_field import rationalise
In [6]: rationalise(ModP(Q(7, 13), 2147483647))
Out [6]: Fraction(7, 13)
In [7]: rationalise(PAdic(Q(7, 13), 2147483647, 12))
Out [7]: Fraction(7, 13)Perfomance comparison with galois for finite fields
Scalar instantiation and operations are faster in pyadic
import numpy
from galois import GF
from pyadic import ModP
from random import randint
GFp = GF(2 ** 31 - 1)
x = randint(0, 2 ** 31 - 1)
%timeit GFp(x)
2.84 µs ± 63.5 ns
%timeit ModP(x, 2 ** 31 - 1)
297 ns ± 0.876 ns
%timeit GFp(x) ** 2
30.1 µs ± 20.6 µs
%timeit ModP(x, 2 ** 31 - 1) ** 2
2.23 µs ± 91.8 nswhile galois is faster for vectorized operations (the bigger the array the bigger the gain)
%timeit numpy.array([randint(0, 2 ** 31 - 1) for i in range(100)]).view(GFp) ** 2
65.6 µs ± 1.86 µs
%timeit numpy.array([ModP(randint(0, 2 ** 31 - 1), 2 ** 31 - 1) for i in range(100)]) ** 2
351 µs ± 9.28 µsHowever, galois requires everything to be appropriately typed, while pyadic performs type-casting on-the-fly
numpy.array([randint(0, 2 ** 31 - 1) for i in range(100)]).view(GFp) / 2
TypeError
numpy.array([ModP(randint(0, 2 ** 31 - 1), 2 ** 31 - 1) for i in range(100)]) / 2
array([...], dtype=object)If you found this library useful, please consider citing it
@inproceedings{DeLaurentis:2023qhd,
author = "De Laurentis, Giuseppe",
title = "{Lips: $p$-adic and singular phase space}",
booktitle = "{21th International Workshop on Advanced Computing and Analysis Techniques in Physics Research}: {AI meets Reality}",
eprint = "2305.14075",
archivePrefix = "arXiv",
primaryClass = "hep-th",
reportNumber = "PSI-PR-23-14",
month = "5",
year = "2023"
}