Repository: mhostetter/galois

Issue:
JIT alternative
Hello,

Galois package has been very useful but I am having issues with the JIT compiled code using numba. Is there a way to turn the JIT compiling off using numba easily? Also, could you point me to where you are using numba for calculating rref and rank in _linalg?

Im aware i will be sacrificing speed but im mainly interested in the fields arithmetic only.

Thanks!


Discussion:

Patch:
diff --git a/src/galois/_domains/_calculate.py b/src/galois/_domains/_calculate.py
index 708a72234..c93cd68cd 100644
--- a/src/galois/_domains/_calculate.py
+++ b/src/galois/_domains/_calculate.py
@@ -464,7 +464,7 @@ class reciprocal_itoh_tsujii(_lookup.reciprocal_ufunc):
         ORDER = self.field.order
         MULTIPLY = self.field._multiply.ufunc
         POSITIVE_POWER = self.field._positive_power.ufunc
-        SUBFIELD_RECIPROCAL = self.field.prime_subfield._reciprocal.ufunc
+        SUBFIELD_RECIPROCAL = getattr(self.field.prime_subfield._reciprocal, self.field.ufunc_mode.replace("-", "_"))
 
     @staticmethod
     def calculate(a: int) -> int:
diff --git a/src/galois/_domains/_meta.py b/src/galois/_domains/_meta.py
index 5ff81fdf5..892bf549f 100644
--- a/src/galois/_domains/_meta.py
+++ b/src/galois/_domains/_meta.py
@@ -41,10 +41,10 @@ class ArrayMeta(abc.ABCMeta):
             cls._ufunc_modes = ["python-calculate"]
         elif cls._order <= 2**20:
             cls._default_ufunc_mode = "jit-lookup"
-            cls._ufunc_modes = ["jit-lookup", "jit-calculate"]
+            cls._ufunc_modes = ["jit-lookup", "jit-calculate", "python-calculate"]
         else:
             cls._default_ufunc_mode = "jit-calculate"
-            cls._ufunc_modes = ["jit-lookup", "jit-calculate"]
+            cls._ufunc_modes = ["jit-lookup", "jit-calculate", "python-calculate"]
         cls._ufunc_mode = None  # This is set in the first call to compile
 
         cls._name = "Undefined"  # Needs overridden
diff --git a/src/galois/_domains/_ufunc.py b/src/galois/_domains/_ufunc.py
index 6f85b633d..72168b6da 100644
--- a/src/galois/_domains/_ufunc.py
+++ b/src/galois/_domains/_ufunc.py
@@ -516,6 +516,8 @@ class log_ufunc(UFunc):
         inputs = list(inputs) + [int(self.field.primitive_element)]
         inputs, kwargs = self._view_inputs_as_ndarray(inputs, kwargs)
         output = getattr(self.ufunc, method)(*inputs, **kwargs)
+        if output.dtype == np.object_:
+            output = output.astype(int)
         return output
 
 
diff --git a/src/galois/_fields/_array.py b/src/galois/_fields/_array.py
index 61b590727..5cf847d38 100644
--- a/src/galois/_fields/_array.py
+++ b/src/galois/_fields/_array.py
@@ -1730,6 +1730,8 @@ class FieldArray(Array, metaclass=FieldArrayMeta):
 
         if np.isscalar(output):
             output = int(output)
+        if output.dtype == np.object_:
+            output = output.astype(int)
 
         return output
 
diff --git a/src/galois/_fields/_gf2.py b/src/galois/_fields/_gf2.py
index ad40b40f8..212feed11 100644
--- a/src/galois/_fields/_gf2.py
+++ b/src/galois/_fields/_gf2.py
@@ -153,5 +153,5 @@ class GF2(
 
 
 GF2._default_ufunc_mode = "jit-calculate"
-GF2._ufunc_modes = ["jit-calculate"]
+GF2._ufunc_modes = ["jit-calculate", "python-calculate"]
 GF2.compile("auto")


Test patch:
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index 618c48c9d..8217082ed 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -80,19 +80,9 @@ jobs:
     if: ${{ github.event_name == 'pull_request' }}
     strategy:
       matrix:
-        os: [ubuntu-latest, macos-latest, windows-latest]
+        os: [ubuntu-latest, macos-13, windows-latest]
         python-version: [3.7, 3.8, 3.9, '3.10', 3.11, 3.12]
-        # https://github.com/actions/runner-images/issues/9770#issuecomment-2085623315
-        exclude:  # Python < v3.8 does not support Apple Silicon ARM64
-          - python-version: "3.7"
-            os: macos-latest
-          - python-version: "3.8"
-            os: macos-latest
-        include:  # So run those legacy versions on Intel CPUs
-          - python-version: "3.7"
-            os: macos-13
-          - python-version: "3.8"
-            os: macos-13
+      fail-fast: false
     runs-on: ${{ matrix.os }}
     steps:
       - uses: actions/checkout@v3
@@ -153,6 +143,7 @@ jobs:
         include:  # So run those legacy versions on Intel CPUs
           - python-version: "3.7"
             os: macos-13
+      fail-fast: false
     runs-on: ${{ matrix.os }}
     steps:
       - uses: actions/checkout@v3
diff --git a/tests/fields/conftest.py b/tests/fields/conftest.py
index 1b30fac64..a60645d0c 100644
--- a/tests/fields/conftest.py
+++ b/tests/fields/conftest.py
@@ -38,6 +38,7 @@ FIELDS = [
 FIELDS_DIFF_MODES = [
     # Binary field
     pytest.param("GF(2)-jit-calculate"),
+    pytest.param("GF(2)-python-calculate"),
     # Binary extension fields
     pytest.param("GF(2^2)-jit-lookup"),
     pytest.param("GF(2^2)-jit-calculate"),
@@ -52,8 +53,10 @@ FIELDS_DIFF_MODES = [
     # Prime fields
     pytest.param("GF(5)-jit-lookup"),
     pytest.param("GF(5)-jit-calculate"),
+    pytest.param("GF(5)-python-calculate"),
     pytest.param("GF(7)-jit-lookup"),
     pytest.param("GF(7)-jit-calculate"),
+    pytest.param("GF(7)-python-calculate"),
     pytest.param("GF(31)-jit-lookup"),
     pytest.param("GF(31)-jit-calculate"),
     pytest.param("GF(3191)-jit-lookup"),
@@ -76,7 +79,7 @@ def construct_field(folder):
         ufunc_mode = "auto"
 
     if folder == "GF(2)":
-        GF = galois.GF2
+        GF = galois.GF(2, compile=ufunc_mode)
 
     elif folder == "GF(5)":
         GF = galois.GF(5, compile=ufunc_mode)
diff --git a/tests/fields/test_arithmetic.py b/tests/fields/test_arithmetic.py
index d0eb7e623..5465c8425 100644
--- a/tests/fields/test_arithmetic.py
+++ b/tests/fields/test_arithmetic.py
@@ -5,6 +5,7 @@ A pytest module to test the accuracy of FieldArray arithmetic.
 import random
 
 import numpy as np
+import pytest
 
 import galois
 
@@ -218,11 +219,12 @@ def test_log_different_base(field_log):
     assert np.array_equal(beta**z, x)
 
 
-def test_log_pollard_rho():
+@pytest.mark.parametrize("ufunc_mode", ["jit-calculate", "python-calculate"])
+def test_log_pollard_rho(ufunc_mode):
     """
     The Pollard-rho discrete logarithm algorithm is only applicable for fields when p^m - 1 is prime.
     """
-    GF = galois.GF(2**19, compile="jit-calculate")
+    GF = galois.GF(2**5, compile=ufunc_mode)
     assert isinstance(GF._log, galois._domains._calculate.log_pollard_rho)
     dtype = random.choice(GF.dtypes)
     x = GF.Random(10, low=1, dtype=dtype)