Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.4.1 #560

Merged
merged 7 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The new ufuncs are written in pure Python and [just-in-time compiled](https://nu

## Features

- Supports all [Galois fields](https://mhostetter.github.io/galois/latest/api/galois.GF/) $\mathrm{GF}(p^m)$, even arbitrarily-large fields!
- Supports all [Galois fields](https://mhostetter.github.io/galois/latest/api/galois.GF/) $\mathrm{GF}(p^m)$, even arbitrarily large fields!
- [**Faster**](https://mhostetter.github.io/galois/latest/performance/prime-fields/) than native NumPy! `GF(x) * GF(y)` is faster than `(x * y) % p` for $\mathrm{GF}(p)$.
- Seamless integration with NumPy -- normal NumPy functions work on [`FieldArray`](https://mhostetter.github.io/galois/latest/api/galois.FieldArray/)s.
- Linear algebra over finite fields using normal [`np.linalg`](https://mhostetter.github.io/galois/latest/basic-usage/array-arithmetic/#linear-algebra) functions.
Expand Down Expand Up @@ -76,7 +76,7 @@ Import the `galois` package in Python.
In [1]: import galois

In [2]: galois.__version__
Out[2]: '0.4.0'
Out[2]: '0.4.1'
```

### Create a [`FieldArray`](https://mhostetter.github.io/galois/latest/api/galois.FieldArray/) subclass
Expand Down
4 changes: 2 additions & 2 deletions docs/basic-usage/array-arithmetic.rst
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ Advanced arithmetic
:collapsible:

The Discrete Fourier Transform (DFT) of size $n$ over the finite field $\mathrm{GF}(p^m)$ exists when
there exists a primitive $n$-th root of unity. This occurs when $n\ |\ p^m - 1$.
there exists a primitive $n$-th root of unity. This occurs when $n \mid p^m - 1$.

.. ipython-with-reprs:: int,poly,power

Expand All @@ -310,7 +310,7 @@ Advanced arithmetic
:collapsible:

The inverse Discrete Fourier Transform (DFT) of size $n$ over the finite field $\mathrm{GF}(p^m)$
exists when there exists a primitive $n$-th root of unity. This occurs when $n\ |\ p^m - 1$.
exists when there exists a primitive $n$-th root of unity. This occurs when $n \mid p^m - 1$.

.. ipython-with-reprs:: int,poly,power

Expand Down
8 changes: 8 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@
"icon": "fontawesome/solid/quote-left",
"override": True,
},
{
"name": "question",
"title": "Question",
"classes": ["collapsible"],
"icon": "fontawesome/solid/question",
"color": (108, 117, 125), # --sd-color-secondary
"override": True,
},
{
"name": "seealso",
"title": "See also",
Expand Down
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ calculation (for memory savings).
Features
--------

- Supports all Galois fields $\mathrm{GF}(p^m)$, even arbitrarily-large fields!
- Supports all Galois fields $\mathrm{GF}(p^m)$, even arbitrarily large fields!
- **Faster** than native NumPy! `GF(x) * GF(y)` is faster than `(x * y) % p` for $\mathrm{GF}(p)$.
- Seamless integration with NumPy -- normal NumPy functions work on :obj:`~galois.FieldArray` instances.
- Linear algebra over finite fields using normal :obj:`numpy.linalg` functions.
Expand Down
10 changes: 5 additions & 5 deletions docs/release-notes/v0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ Poly(1, GF(2))
- Allow polynomial comparison with integers and field scalars. Now `galois.Poly([0]) == 0` and `galois.Poly([0]) == GF(0)` return `True` rather than raising `TypeError`.
- Support testing 0-degree polynomials for irreducibility and primitivity.
- Extend `crt()` to work over non co-prime moduli.
- Extend `prev_prime()` and `next_prime()` to work over arbitrarily-large inputs.
- Extend `prev_prime()` and `next_prime()` to work over arbitrarily large inputs.
- Allow negative integer inputs to `primes()`, `is_prime()`, `is_composite()`, `is_prime_power()`, `is_perfect_power()`, `is_square_free()`, `is_smooth()`, and `is_powersmooth()`.
- Fix various type hinting errors.
- Various other bug fixes.
Expand Down Expand Up @@ -715,8 +715,8 @@ Poly(1, GF(2))
- Moved `galois.square_free_factorization()` function into `Poly.square_free_factors()` method. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.distinct_degree_factorization()` function into `Poly.distinct_degree_factors()` method. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.equal_degree_factorization()` function into `Poly.equal_degree_factors()` method. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.is_irreducible()` function into `Poly.is_irreducible()` method. This is a method, not property, to indicate it is a computationally-expensive operation. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.is_primitive()` function into `Poly.is_primitive()` method. This is a method, not property, to indicate it is a computationally-expensive operation. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.is_irreducible()` function into `Poly.is_irreducible()` method. This is a method, not property, to indicate it is a computationally expensive operation. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.is_primitive()` function into `Poly.is_primitive()` method. This is a method, not property, to indicate it is a computationally expensive operation. ([#362](https://github.com/mhostetter/galois/pull/362))
- Moved `galois.is_monic()` function into `Poly.is_monic` property. ([#362](https://github.com/mhostetter/galois/pull/362))

### Changes
Expand All @@ -742,7 +742,7 @@ Poly(1, GF(2))
- Added `galois.get_printoptions()` function to return the current package-wide printing options. This is the equivalent of `np.get_printoptions()`. ([#363](https://github.com/mhostetter/galois/pull/363))
- Added `galois.printoptions()` context manager to modify printing options inside of a `with` statement. This is the equivalent of `np.printoptions()`. ([#363](https://github.com/mhostetter/galois/pull/363))
- Added a separate `Poly.factors()` method, in addition to the polymorphic `galois.factors()`. ([#362](https://github.com/mhostetter/galois/pull/362))
- Added a separate `Poly.is_square_free()` method, in addition to the polymorphic `galois.is_square_free()`. This is a method, not property, to indicate it is a computationally-expensive operation. ([#362](https://github.com/mhostetter/galois/pull/362))
- Added a separate `Poly.is_square_free()` method, in addition to the polymorphic `galois.is_square_free()`. This is a method, not property, to indicate it is a computationally expensive operation. ([#362](https://github.com/mhostetter/galois/pull/362))
- Fixed a bug (believed to be introduced in v0.0.26) where `Poly.degree` occasionally returned `np.int64` instead of `int`. This could cause overflow in certain large integer operations (e.g., computing $q^m$ when determining if a degree-$m$ polynomial over $\mathrm{GF}(q)$ is irreducible). When the integer overflowed, this created erroneous results. ([#360](https://github.com/mhostetter/galois/issues/360), [#361](https://github.com/mhostetter/galois/pull/361))
- Increased code coverage.

Expand All @@ -756,7 +756,7 @@ Poly(1, GF(2))

### Changes

- Added support for NumPy 1.22 with Numba 0.55.2. This allows users to upgrade NumPy and avoid recently-discovered vulnerabilities [CVE-2021-34141](https://nvd.nist.gov/vuln/detail/CVE-2021-34141), [CVE-2021-41496](https://nvd.nist.gov/vuln/detail/CVE-2021-41496), and [CVE-2021-41495](https://nvd.nist.gov/vuln/detail/CVE-2021-41495). ([#366](https://github.com/mhostetter/galois/pull/366))
- Added support for NumPy 1.22 with Numba 0.55.2. This allows users to upgrade NumPy and avoid recently discovered vulnerabilities [CVE-2021-34141](https://nvd.nist.gov/vuln/detail/CVE-2021-34141), [CVE-2021-41496](https://nvd.nist.gov/vuln/detail/CVE-2021-41496), and [CVE-2021-41495](https://nvd.nist.gov/vuln/detail/CVE-2021-41495). ([#366](https://github.com/mhostetter/galois/pull/366))
- Made `FieldArray.repr_table()` more compact. ([#367](https://github.com/mhostetter/galois/pull/367))
```ipython
In [2]: GF = galois.GF(3**3)
Expand Down
2 changes: 1 addition & 1 deletion docs/release-notes/v0.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ tocdepth: 2
Poly(x^9 + 3x^2 + 4, GF(7))
```
- Added a database of binary irreducible polynomials with degrees less than 10,000. These polynomials are
lexicographically-first and have the minimum number of non-zero terms. The database is accessed in
lexicographically first and have the minimum number of non-zero terms. The database is accessed in
`irreducible_poly()` when `terms="min"` and `method="min"`. ([#462](https://github.com/mhostetter/galois/pull/462))
```ipython
In [1]: import galois
Expand Down
17 changes: 17 additions & 0 deletions docs/release-notes/v0.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,20 @@ tocdepth: 2

- Iyán Méndez Veiga ([@iyanmv](https://github.com/iyanmv))
- Matt Hostetter ([@mhostetter](https://github.com/mhostetter))

## v0.4.1

*Released July 6, 2024*

### Changes

- Fixed multithreading incompatibility. Previously only one thread could read from the SQLite databases. ([#558](https://github.com/mhostetter/galois/pull/558))
- Clarified `Poly` string representation when underlying field is non-primitive and uses the `"poly"` element representation. ([#329](https://github.com/mhostetter/galois/issues/329))
- Fixed typo in error message. ([#557](https://github.com/mhostetter/galois/pull/557))
- Made minor documentation improvements.

### Contributors

- Semjon Kravtšenko ([@semjon00](https://github.com/semjon00))
- [@MrVeka](https://github.com/MrVeka)
- Matt Hostetter ([@mhostetter](https://github.com/mhostetter))
8 changes: 4 additions & 4 deletions src/galois/_codes/_linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,11 +383,11 @@ def generator_to_parity_check_matrix(G: FieldArray) -> FieldArray:

Arguments:
G: The $(k, n)$ generator matrix $\mathbf{G}$ in systematic form
$\mathbf{G} = [\mathbf{I}_{k,k}\ |\ \mathbf{P}_{k,n-k}]$.
$\mathbf{G} = [\mathbf{I}_{k,k} \mid \mathbf{P}_{k,n-k}]$.

Returns:
The $(n-k, n)$ parity-check matrix
$\mathbf{H} = [-\mathbf{P}_{k,n-k}^T\ |\ \mathbf{I}_{n-k,n-k}]$`.
$\mathbf{H} = [-\mathbf{P}_{k,n-k}^T \mid \mathbf{I}_{n-k,n-k}]$`.

Examples:
.. ipython:: python
Expand Down Expand Up @@ -423,10 +423,10 @@ def parity_check_to_generator_matrix(H: FieldArray) -> FieldArray:

Arguments:
H: The $(n-k, n)$ parity-check matrix $\mathbf{G}$ in systematic form
$\mathbf{H} = [-\mathbf{P}_{k,n-k}^T\ |\ \mathbf{I}_{n-k,n-k}]$`.
$\mathbf{H} = [-\mathbf{P}_{k,n-k}^T \mid \mathbf{I}_{n-k,n-k}]$`.

Returns:
The $(k, n)$ generator matrix $\mathbf{G} = [\mathbf{I}_{k,k}\ |\ \mathbf{P}_{k,n-k}]$.
The $(k, n)$ generator matrix $\mathbf{G} = [\mathbf{I}_{k,k} \mid \mathbf{P}_{k,n-k}]$.

Examples:
.. ipython:: python
Expand Down
73 changes: 38 additions & 35 deletions src/galois/_databases/_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,32 @@
import sqlite3
import sys
from pathlib import Path
from threading import Lock


class DatabaseInterface:
"""
An abstract class to interface with SQLite databases.
"""

singleton = None
_lock = Lock()
_singleton = None
file: Path

def __new__(cls):
if cls.singleton is None:
cls.singleton = super().__new__(cls)
cls.conn = sqlite3.connect(cls.file)
cls.cursor = cls.conn.cursor()
return cls.singleton
with cls._lock:
if cls._singleton is None:
cls._singleton = super().__new__(cls)
cls.conn = sqlite3.connect(cls.file, check_same_thread=False)
cls.cursor = cls.conn.cursor()
return cls._singleton


class PrimeFactorsDatabase(DatabaseInterface):
"""
A class to interface with the prime factors database.
"""

singleton = None
file = Path(__file__).parent / "prime_factors.db"

def fetch(self, n: int) -> tuple[list[int], list[int], int]:
Expand All @@ -51,15 +53,16 @@ def fetch(self, n: int) -> tuple[list[int], list[int], int]:
n = str(n)
sys.set_int_max_str_digits(default_limit)

self.cursor.execute(
"""
SELECT factors, multiplicities, composite
FROM factorizations
WHERE value=?
""",
(str(n),),
)
result = self.cursor.fetchone()
with self._lock:
self.cursor.execute(
"""
SELECT factors, multiplicities, composite
FROM factorizations
WHERE value=?
""",
(str(n),),
)
result = self.cursor.fetchone()

if result is None:
raise LookupError(f"The prime factors database does not contain an entry for {n}.")
Expand All @@ -76,7 +79,6 @@ class IrreduciblePolyDatabase(DatabaseInterface):
A class to interface with the irreducible polynomials database.
"""

singleton = None
file = Path(__file__).parent / "irreducible_polys.db"

def fetch(self, characteristic: int, degree: int) -> tuple[list[int], list[int]]:
Expand All @@ -90,14 +92,15 @@ def fetch(self, characteristic: int, degree: int) -> tuple[list[int], list[int]]
Returns:
A tuple containing the non-zero degrees and coefficients of the irreducible polynomial.
"""
self.cursor.execute(
"""
SELECT nonzero_degrees, nonzero_coeffs
FROM polys
WHERE characteristic=? AND degree=?""",
(characteristic, degree),
)
result = self.cursor.fetchone()
with self._lock:
self.cursor.execute(
"""
SELECT nonzero_degrees, nonzero_coeffs
FROM polys
WHERE characteristic=? AND degree=?""",
(characteristic, degree),
)
result = self.cursor.fetchone()

if result is None:
raise LookupError(
Expand All @@ -116,7 +119,6 @@ class ConwayPolyDatabase(DatabaseInterface):
A class to interface with the Conway polynomials database.
"""

singleton = None
file = Path(__file__).parent / "conway_polys.db"

def fetch(self, characteristic: int, degree: int) -> tuple[list[int], list[int]]:
Expand All @@ -130,15 +132,16 @@ def fetch(self, characteristic: int, degree: int) -> tuple[list[int], list[int]]
Returns:
A tuple containing the non-zero degrees and coefficients of the Conway polynomial.
"""
self.cursor.execute(
"""
SELECT nonzero_degrees, nonzero_coeffs
FROM polys
WHERE characteristic=? AND degree=?
""",
(characteristic, degree),
)
result = self.cursor.fetchone()
with self._lock:
self.cursor.execute(
"""
SELECT nonzero_degrees, nonzero_coeffs
FROM polys
WHERE characteristic=? AND degree=?
""",
(characteristic, degree),
)
result = self.cursor.fetchone()

if result is None:
raise LookupError(
Expand Down
2 changes: 1 addition & 1 deletion src/galois/_fields/_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def _verify_array_like_types_and_values(cls, x: ElementLike | ArrayLike) -> Elem
if isinstance(x, (int, np.integer)):
cls._verify_scalar_value(x)
elif isinstance(x, cls):
# This was a previously-created and vetted array -- there's no need to re-verify
# This was a previously created and vetted array -- there's no need to re-verify
if x.ndim == 0:
# Ensure that in "large" fields with dtype=object that FieldArray objects aren't assigned to the array.
# The arithmetic functions are designed to operate on Python ints.
Expand Down
8 changes: 4 additions & 4 deletions src/galois/_fields/_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def GF(
:func:`~galois.FieldArray.compile` method. See :doc:`/basic-usage/compilation-modes` for a further
discussion.

- `None` (default): For a newly-created :obj:`~galois.FieldArray` subclass, `None` corresponds to
- `None` (default): For a newly created :obj:`~galois.FieldArray` subclass, `None` corresponds to
`"auto"`. If the :obj:`~galois.FieldArray` subclass already exists, `None` does not modify its current
compilation mode.
- `"auto"`: Selects `"jit-lookup"` for fields with order less than $2^{20}$, `"jit-calculate"` for
Expand All @@ -109,7 +109,7 @@ def GF(
:func:`~galois.FieldArray.repr` method. See :doc:`/basic-usage/element-representation` for a further
discussion.

- `None` (default): For a newly-created :obj:`~galois.FieldArray` subclass, `None` corresponds to `"int"`.
- `None` (default): For a newly created :obj:`~galois.FieldArray` subclass, `None` corresponds to `"int"`.
If the :obj:`~galois.FieldArray` subclass already exists, `None` does not modify its current element
representation.
- `"int"`: Sets the element representation to the :ref:`integer representation <int-repr>`.
Expand Down Expand Up @@ -191,7 +191,7 @@ def GF(
GF = galois.GF(3**5, irreducible_poly="x^5 + 2x + 2")
print(GF.properties)

Finite fields with arbitrarily-large orders are supported.
Finite fields with arbitrarily large orders are supported.

.. md-tab-set::

Expand Down Expand Up @@ -246,7 +246,7 @@ def GF(
verify_isinstance(order, int)
p, e = factors(order)
if not len(p) == len(e) == 1:
s = " + ".join([f"{pi}**{ei}" for pi, ei in zip(p, e)])
s = " * ".join([f"{pi}^{ei}" for pi, ei in zip(p, e)])
raise ValueError(f"Argument 'order' must be a prime power, not {order} = {s}.")
characteristic, degree = p[0], e[0]
elif len(args) == 2:
Expand Down
2 changes: 1 addition & 1 deletion src/galois/_modular.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def euler_phi(n: int) -> int:
Notes:
This function implements the Euler totient function

$$\phi(n) = n \prod_{p\ |\ n} \bigg(1 - \frac{1}{p}\bigg) = \prod_{i=1}^{k} p_i^{e_i-1} \big(p_i - 1\big)$$
$$\phi(n) = n \prod_{p \mid n} \bigg(1 - \frac{1}{p}\bigg) = \prod_{i=1}^{k} p_i^{e_i-1} \big(p_i - 1\big)$$

for prime $p$ and the prime factorization $n = p_1^{e_1} \dots p_k^{e_k}$.

Expand Down
11 changes: 11 additions & 0 deletions src/galois/_polys/_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,21 @@
# Use brackets around coefficients only when using the "poly" or "power" element representation
brackets = hasattr(type(coeffs), "_element_repr") and type(coeffs)._element_repr in ["poly", "power"]

# If the element representation is polynomial and the irreducible polynomial is not primitive, convert x to z
# for the coefficients
convert_x_to_z = (
hasattr(type(coeffs), "_element_repr")
and type(coeffs)._element_repr == "poly"
and not type(coeffs).is_primitive_poly
)

for degree, coeff in zip(degrees, coeffs):
if coeff == 0:
continue

if convert_x_to_z and coeff != 1:
coeff = str(coeff).replace("x", "z")

Check warning on line 110 in src/galois/_polys/_conversions.py

View check run for this annotation

Codecov / codecov/patch

src/galois/_polys/_conversions.py#L110

Added line #L110 was not covered by tests

if degree > 1:
if coeff == 1:
c = ""
Expand Down
Loading
Loading