diff --git a/galois/_fields/_main.py b/galois/_fields/_main.py index d0101a8fb..67edb17ec 100644 --- a/galois/_fields/_main.py +++ b/galois/_fields/_main.py @@ -3778,30 +3778,54 @@ def __len__(self) -> int: return self.degree + 1 def _check_inputs_are_polys(self, a, b): + """ + Verify polynomial arithmetic operands are either galois.Poly or scalars in a finite field. + """ if not isinstance(a, (Poly, self.field)): - raise TypeError(f"Both operands must be a galois.Poly or a single element of its field {b.field.name}, not {type(a)}.") + raise TypeError(f"Both operands must be a galois.Poly or a single element of its field {self.field.name}, not {type(a)}.") if not isinstance(b, (Poly, self.field)): - raise TypeError(f"Both operands must be a galois.Poly or a single element of its field {a.field.name}, not {type(b)}.") + raise TypeError(f"Both operands must be a galois.Poly or a single element of its field {self.field.name}, not {type(b)}.") + if (isinstance(a, Poly) and isinstance(b, Poly)) and not a.field is b.field: + raise TypeError(f"Both polynomial operands must be over the same field, not {a.field.name} and {b.field.name}.") + + def _check_inputs_are_polys_or_ints(self, a, b): + """ + Verify polynomial arithmetic operands are either galois.Poly, scalars in a finite field, or an integer (scalar multiplication). + """ + if not isinstance(a, (Poly, self.field, int, np.integer)): + raise TypeError(f"Both operands must be a galois.Poly, a single element of its field {self.field.name}, or an integer, not {type(a)}.") + if not isinstance(b, (Poly, self.field, int, np.integer)): + raise TypeError(f"Both operands must be a galois.Poly, a single element of its field {self.field.name}, or an integer, not {type(b)}.") + if (isinstance(a, Poly) and isinstance(b, Poly)) and not a.field is b.field: + raise TypeError(f"Both polynomial operands must be over the same field, not {a.field.name} and {b.field.name}.") + def _convert_field_scalars_to_polys(self, a, b): + """ + Convert finite field scalars to 0-degree polynomials in that field. + """ # Promote a single field element to a 0-degree polynomial - if not isinstance(a, Poly): + if isinstance(a, self.field): if not a.size == 1: raise ValueError(f"Arguments that are Galois field elements must have size 1 (equivalently a 0-degree polynomial), not size {a.size}.") a = Poly(np.atleast_1d(a)) - if not isinstance(b, Poly): + if isinstance(b, self.field): if not b.size == 1: raise ValueError(f"Arguments that are Galois field elements must have size 1 (equivalently a 0-degree polynomial), not size {b.size}.") b = Poly(np.atleast_1d(b)) - if not a.field is b.field: - raise TypeError(f"Both polynomial operands must be over the same field, not {str(a.field)} and {str(b.field)}.") + return a, b + @staticmethod + def _determine_poly_class(a, b): + """ + Determine the type of polynomial arithmetic to perform. + """ if isinstance(a, SparsePoly) or isinstance(b, SparsePoly): - return SparsePoly, a, b + return SparsePoly elif isinstance(a, BinaryPoly) or isinstance(b, BinaryPoly): - return BinaryPoly, a, b + return BinaryPoly else: - return DensePoly, a, b + return DensePoly def __add__(self, other): """ @@ -3825,11 +3849,15 @@ def __add__(self, other): b = galois.Poly.Random(3); b a + b """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._add(a, b) def __radd__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._add(b, a) def __sub__(self, other): @@ -3854,11 +3882,15 @@ def __sub__(self, other): b = galois.Poly.Random(3); b a - b """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._sub(a, b) def __rsub__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._sub(b, a) def __mul__(self, other): @@ -3883,11 +3915,21 @@ def __mul__(self, other): b = galois.Poly.Random(3); b a * b """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys_or_ints(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + if isinstance(a, (int, np.integer)): + # Ensure the integer is in the second operand for scalar multiplication + a, b = b, a + cls = self._determine_poly_class(a, b) return cls._mul(a, b) def __rmul__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys_or_ints(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + if isinstance(b, (int, np.integer)): + # Ensure the integer is in the second operand for scalar multiplication + b, a = a, b + cls = self._determine_poly_class(a, b) return cls._mul(b, a) def __divmod__(self, other): @@ -3916,11 +3958,15 @@ def __divmod__(self, other): q, r b*q + r """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._divmod(a, b) def __rdivmod__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._divmod(b, a) def __truediv__(self, other): @@ -3948,11 +3994,15 @@ def __truediv__(self, other): divmod(a, b) a / b """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._divmod(a, b)[0] def __rtruediv__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._divmod(b, a)[0] def __floordiv__(self, other): @@ -3980,11 +4030,15 @@ def __floordiv__(self, other): divmod(a, b) a // b """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._divmod(a, b)[0] def __rfloordiv__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._divmod(b, a)[0] def __mod__(self, other): @@ -4010,11 +4064,15 @@ def __mod__(self, other): divmod(a, b) a % b """ - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._mod(a, b) def __rmod__(self, other): - cls, a, b = self._check_inputs_are_polys(self, other) + self._check_inputs_are_polys(self, other) + a, b = self._convert_field_scalars_to_polys(self, other) + cls = self._determine_poly_class(a, b) return cls._mod(b, a) def __pow__(self, other): @@ -4043,7 +4101,8 @@ def __pow__(self, other): raise TypeError(f"For polynomial exponentiation, the second argument must be an int, not {other}.") if not other >= 0: raise ValueError(f"Can only exponentiate polynomials to non-negative integers, not {other}.") - field, a, power = self.field, self, other + a, power = self, other + field = self.field # c(x) = a(x) ** power if power == 0: @@ -4074,11 +4133,11 @@ def __eq__(self, other): elif isinstance(other, FieldArray): # Compare poly to a finite field scalar (may or may not be from the same field) if not other.ndim == 0: - raise ValueError(f"Can only compare Poly to a 0-D FieldArray scalar, not shape {other.shape}.") + raise ValueError(f"Can only compare galois.Poly to a 0-D galois.FieldArray scalar, not shape {other.shape}.") return self.field is type(other) and self.degree == 0 and np.array_equal(self.coeffs, np.atleast_1d(other)) elif not isinstance(other, Poly): - raise TypeError(f"Can only compare Poly and Poly / int / FieldArray scalar objects, not {type(other)}.") + raise TypeError(f"Can only compare galois.Poly and galois.Poly / int / galois.FieldArray scalar objects, not {type(other)}.") else: # Compare two poly objects to each other @@ -4310,8 +4369,12 @@ def _sub(cls, a, b): @classmethod def _mul(cls, a, b): - # c(x) = a(x) * b(x) - c_coeffs = np.convolve(a.coeffs, b.coeffs) + if isinstance(b, (int, np.integer)): + # Scalar multiplication (p * 3 = p + p + p) + c_coeffs = a.coeffs * b + else: + # c(x) = a(x) * b(x) + c_coeffs = np.convolve(a.coeffs, b.coeffs) return Poly(c_coeffs) @@ -4410,20 +4473,25 @@ def _sub(cls, a, b): @classmethod def _mul(cls, a, b): - # Re-order operands such that a > b so the while loop has less loops - a = a.integer - b = b.integer - if b > a: - a, b = b, a + if isinstance(b, (int, np.integer)): + # Scalar multiplication (p * 3 = p + p + p) + return BinaryPoly(a.integer) if b % 2 == 1 else BinaryPoly(0) - c = 0 - while b > 0: - if b & 0b1: - c ^= a # Add a(x) to c(x) - b >>= 1 # Divide b(x) by x - a <<= 1 # Multiply a(x) by x + else: + # Re-order operands such that a > b so the while loop has less loops + a = a.integer + b = b.integer + if b > a: + a, b = b, a + + c = 0 + while b > 0: + if b & 0b1: + c ^= a # Add a(x) to c(x) + b >>= 1 # Divide b(x) by x + a <<= 1 # Multiply a(x) by x - return BinaryPoly(c) + return BinaryPoly(c) @classmethod def _divmod(cls, a, b): @@ -4578,13 +4646,18 @@ def _sub(cls, a, b): def _mul(cls, a, b): field = a.field - # c(x) = a(x) * b(x) - cc = {} - for a_degree, a_coeff in zip(a.nonzero_degrees, a.nonzero_coeffs): - for b_degree, b_coeff in zip(b.nonzero_degrees, b.nonzero_coeffs): - cc[a_degree + b_degree] = cc.get(a_degree + b_degree, field(0)) + a_coeff*b_coeff + if isinstance(b, (int, np.integer)): + # Scalar multiplication (p * 3 = p + p + p) + return Poly.Degrees(a.nonzero_degrees, a.nonzero_coeffs * b) - return Poly.Degrees(list(cc.keys()), list(cc.values()), field=field) + else: + # c(x) = a(x) * b(x) + cc = {} + for a_degree, a_coeff in zip(a.nonzero_degrees, a.nonzero_coeffs): + for b_degree, b_coeff in zip(b.nonzero_degrees, b.nonzero_coeffs): + cc[a_degree + b_degree] = cc.get(a_degree + b_degree, field(0)) + a_coeff*b_coeff + + return Poly.Degrees(list(cc.keys()), list(cc.values()), field=field) @classmethod def _divmod(cls, a, b): diff --git a/scripts/generate_field_test_vectors.py b/scripts/generate_field_test_vectors.py index b32334be5..3313cec1a 100644 --- a/scripts/generate_field_test_vectors.py +++ b/scripts/generate_field_test_vectors.py @@ -128,6 +128,7 @@ def make_luts(field, folder, sparse=False): os.mkdir(folder) FIELD = field + characteristic = int(field.characteristic()) order = int(field.order()) dtype = np.int64 if order <= np.iinfo(np.int64).max else object alpha = field.primitive_element() @@ -248,6 +249,19 @@ def make_luts(field, folder, sparse=False): d = {"X": X, "Y": Y, "Z": Z} save_pickle(d, folder, "poly_multiply.pkl") + X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)] + Y = [random.randint(1, 2*characteristic) for i in range(20)] + Z = [] + for i in range(len(X)): + x = ring([F(e) for e in X[i][::-1]]) + y = Y[i] + z = x * y + z = np.array([I(e) for e in z.list()[::-1]], dtype=dtype).tolist() + z = z if z != [] else [0] + Z.append(z) + d = {"X": X, "Y": Y, "Z": Z} + save_pickle(d, folder, "poly_scalar_multiply.pkl") + X = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)] Y = [random_coeffs(0, order, MIN_COEFFS, MAX_COEFFS) for i in range(20)] # Add some specific polynomial types diff --git a/tests/data/fields/GF(109987^4)/poly_divmod.pkl b/tests/data/fields/GF(109987^4)/poly_divmod.pkl index 6c0f100cf..baa0c85aa 100644 Binary files a/tests/data/fields/GF(109987^4)/poly_divmod.pkl and b/tests/data/fields/GF(109987^4)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(109987^4)/poly_evaluate.pkl b/tests/data/fields/GF(109987^4)/poly_evaluate.pkl index 8ba3748b2..770c5bb57 100644 Binary files a/tests/data/fields/GF(109987^4)/poly_evaluate.pkl and b/tests/data/fields/GF(109987^4)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(109987^4)/poly_power.pkl b/tests/data/fields/GF(109987^4)/poly_power.pkl index 7a8858ba0..4744e7960 100644 Binary files a/tests/data/fields/GF(109987^4)/poly_power.pkl and b/tests/data/fields/GF(109987^4)/poly_power.pkl differ diff --git a/tests/data/fields/GF(109987^4)/poly_scalar_multiply.pkl b/tests/data/fields/GF(109987^4)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..8c9cc9501 Binary files /dev/null and b/tests/data/fields/GF(109987^4)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2)/poly_divmod.pkl b/tests/data/fields/GF(2)/poly_divmod.pkl index f4d6f36d6..ec9594dcc 100644 Binary files a/tests/data/fields/GF(2)/poly_divmod.pkl and b/tests/data/fields/GF(2)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2)/poly_evaluate.pkl b/tests/data/fields/GF(2)/poly_evaluate.pkl index 6c267aef5..9f411c77f 100644 Binary files a/tests/data/fields/GF(2)/poly_evaluate.pkl and b/tests/data/fields/GF(2)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2)/poly_power.pkl b/tests/data/fields/GF(2)/poly_power.pkl index dfd4b49f0..c087588b7 100644 Binary files a/tests/data/fields/GF(2)/poly_power.pkl and b/tests/data/fields/GF(2)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..4281fb6d1 Binary files /dev/null and b/tests/data/fields/GF(2)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2147483647)/poly_divmod.pkl b/tests/data/fields/GF(2147483647)/poly_divmod.pkl index d89ae6d58..f41254a79 100644 Binary files a/tests/data/fields/GF(2147483647)/poly_divmod.pkl and b/tests/data/fields/GF(2147483647)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2147483647)/poly_evaluate.pkl b/tests/data/fields/GF(2147483647)/poly_evaluate.pkl index 7ff61c979..87496d7c1 100644 Binary files a/tests/data/fields/GF(2147483647)/poly_evaluate.pkl and b/tests/data/fields/GF(2147483647)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2147483647)/poly_power.pkl b/tests/data/fields/GF(2147483647)/poly_power.pkl index a646b42bb..b245fe774 100644 Binary files a/tests/data/fields/GF(2147483647)/poly_power.pkl and b/tests/data/fields/GF(2147483647)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2147483647)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2147483647)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..6975e3adf Binary files /dev/null and b/tests/data/fields/GF(2147483647)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2^100)/poly_divmod.pkl b/tests/data/fields/GF(2^100)/poly_divmod.pkl index 94851b3ef..262179f38 100644 Binary files a/tests/data/fields/GF(2^100)/poly_divmod.pkl and b/tests/data/fields/GF(2^100)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2^100)/poly_evaluate.pkl b/tests/data/fields/GF(2^100)/poly_evaluate.pkl index ba4f74059..cbd6232ab 100644 Binary files a/tests/data/fields/GF(2^100)/poly_evaluate.pkl and b/tests/data/fields/GF(2^100)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2^100)/poly_power.pkl b/tests/data/fields/GF(2^100)/poly_power.pkl index 68a908958..13ca40f5c 100644 Binary files a/tests/data/fields/GF(2^100)/poly_power.pkl and b/tests/data/fields/GF(2^100)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2^100)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2^100)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..050cf2e68 Binary files /dev/null and b/tests/data/fields/GF(2^100)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2^2)/poly_divmod.pkl b/tests/data/fields/GF(2^2)/poly_divmod.pkl index 3384db963..fb7f5b5e7 100644 Binary files a/tests/data/fields/GF(2^2)/poly_divmod.pkl and b/tests/data/fields/GF(2^2)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2^2)/poly_evaluate.pkl b/tests/data/fields/GF(2^2)/poly_evaluate.pkl index 2df08543d..bc474cfff 100644 Binary files a/tests/data/fields/GF(2^2)/poly_evaluate.pkl and b/tests/data/fields/GF(2^2)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2^2)/poly_power.pkl b/tests/data/fields/GF(2^2)/poly_power.pkl index 35b50802f..0d6f575a4 100644 Binary files a/tests/data/fields/GF(2^2)/poly_power.pkl and b/tests/data/fields/GF(2^2)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2^2)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2^2)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..15697774c Binary files /dev/null and b/tests/data/fields/GF(2^2)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2^3)/poly_divmod.pkl b/tests/data/fields/GF(2^3)/poly_divmod.pkl index 026656ebc..d2e9a8d98 100644 Binary files a/tests/data/fields/GF(2^3)/poly_divmod.pkl and b/tests/data/fields/GF(2^3)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2^3)/poly_evaluate.pkl b/tests/data/fields/GF(2^3)/poly_evaluate.pkl index 37bc2962a..a5fc16487 100644 Binary files a/tests/data/fields/GF(2^3)/poly_evaluate.pkl and b/tests/data/fields/GF(2^3)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2^3)/poly_power.pkl b/tests/data/fields/GF(2^3)/poly_power.pkl index bdb4ffc60..69fa14374 100644 Binary files a/tests/data/fields/GF(2^3)/poly_power.pkl and b/tests/data/fields/GF(2^3)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2^3)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2^3)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..24991a8a2 Binary files /dev/null and b/tests/data/fields/GF(2^3)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2^32)/poly_divmod.pkl b/tests/data/fields/GF(2^32)/poly_divmod.pkl index e39173eb3..96acc5d7d 100644 Binary files a/tests/data/fields/GF(2^32)/poly_divmod.pkl and b/tests/data/fields/GF(2^32)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2^32)/poly_evaluate.pkl b/tests/data/fields/GF(2^32)/poly_evaluate.pkl index 3287da4c1..225ee6edb 100644 Binary files a/tests/data/fields/GF(2^32)/poly_evaluate.pkl and b/tests/data/fields/GF(2^32)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2^32)/poly_power.pkl b/tests/data/fields/GF(2^32)/poly_power.pkl index 3071e4559..a650431cf 100644 Binary files a/tests/data/fields/GF(2^32)/poly_power.pkl and b/tests/data/fields/GF(2^32)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2^32)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2^32)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..cf40cabbc Binary files /dev/null and b/tests/data/fields/GF(2^32)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2^8)/poly_divmod.pkl b/tests/data/fields/GF(2^8)/poly_divmod.pkl index f28e03997..7f192ec4f 100644 Binary files a/tests/data/fields/GF(2^8)/poly_divmod.pkl and b/tests/data/fields/GF(2^8)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2^8)/poly_evaluate.pkl b/tests/data/fields/GF(2^8)/poly_evaluate.pkl index 0769b132b..9ead024da 100644 Binary files a/tests/data/fields/GF(2^8)/poly_evaluate.pkl and b/tests/data/fields/GF(2^8)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2^8)/poly_power.pkl b/tests/data/fields/GF(2^8)/poly_power.pkl index 23fbee108..537fd15eb 100644 Binary files a/tests/data/fields/GF(2^8)/poly_power.pkl and b/tests/data/fields/GF(2^8)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2^8)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2^8)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..b5d4d6617 Binary files /dev/null and b/tests/data/fields/GF(2^8)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(2^8, 283, 19)/poly_divmod.pkl b/tests/data/fields/GF(2^8, 283, 19)/poly_divmod.pkl index 37ba63ffc..676978821 100644 Binary files a/tests/data/fields/GF(2^8, 283, 19)/poly_divmod.pkl and b/tests/data/fields/GF(2^8, 283, 19)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(2^8, 283, 19)/poly_evaluate.pkl b/tests/data/fields/GF(2^8, 283, 19)/poly_evaluate.pkl index 36af6c436..85f4ccf20 100644 Binary files a/tests/data/fields/GF(2^8, 283, 19)/poly_evaluate.pkl and b/tests/data/fields/GF(2^8, 283, 19)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(2^8, 283, 19)/poly_power.pkl b/tests/data/fields/GF(2^8, 283, 19)/poly_power.pkl index 6d570da92..0b5b2196f 100644 Binary files a/tests/data/fields/GF(2^8, 283, 19)/poly_power.pkl and b/tests/data/fields/GF(2^8, 283, 19)/poly_power.pkl differ diff --git a/tests/data/fields/GF(2^8, 283, 19)/poly_scalar_multiply.pkl b/tests/data/fields/GF(2^8, 283, 19)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..47791dabe Binary files /dev/null and b/tests/data/fields/GF(2^8, 283, 19)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(31)/poly_divmod.pkl b/tests/data/fields/GF(31)/poly_divmod.pkl index 3ded046ca..f47c03fb5 100644 Binary files a/tests/data/fields/GF(31)/poly_divmod.pkl and b/tests/data/fields/GF(31)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(31)/poly_evaluate.pkl b/tests/data/fields/GF(31)/poly_evaluate.pkl index 2f8613729..65215b201 100644 Binary files a/tests/data/fields/GF(31)/poly_evaluate.pkl and b/tests/data/fields/GF(31)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(31)/poly_power.pkl b/tests/data/fields/GF(31)/poly_power.pkl index 1b4285603..017832571 100644 Binary files a/tests/data/fields/GF(31)/poly_power.pkl and b/tests/data/fields/GF(31)/poly_power.pkl differ diff --git a/tests/data/fields/GF(31)/poly_scalar_multiply.pkl b/tests/data/fields/GF(31)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..2a2aaef3e Binary files /dev/null and b/tests/data/fields/GF(31)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(3191)/poly_divmod.pkl b/tests/data/fields/GF(3191)/poly_divmod.pkl index e4176d785..f9581b6a6 100644 Binary files a/tests/data/fields/GF(3191)/poly_divmod.pkl and b/tests/data/fields/GF(3191)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(3191)/poly_evaluate.pkl b/tests/data/fields/GF(3191)/poly_evaluate.pkl index 3d4cfb233..fea9b4e09 100644 Binary files a/tests/data/fields/GF(3191)/poly_evaluate.pkl and b/tests/data/fields/GF(3191)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(3191)/poly_power.pkl b/tests/data/fields/GF(3191)/poly_power.pkl index 4d9425a49..10215d72e 100644 Binary files a/tests/data/fields/GF(3191)/poly_power.pkl and b/tests/data/fields/GF(3191)/poly_power.pkl differ diff --git a/tests/data/fields/GF(3191)/poly_scalar_multiply.pkl b/tests/data/fields/GF(3191)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..f1fa43a5d Binary files /dev/null and b/tests/data/fields/GF(3191)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(36893488147419103183)/poly_divmod.pkl b/tests/data/fields/GF(36893488147419103183)/poly_divmod.pkl index 7784ea792..f809b5a73 100644 Binary files a/tests/data/fields/GF(36893488147419103183)/poly_divmod.pkl and b/tests/data/fields/GF(36893488147419103183)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(36893488147419103183)/poly_evaluate.pkl b/tests/data/fields/GF(36893488147419103183)/poly_evaluate.pkl index 0a92edc72..ce9ca6542 100644 Binary files a/tests/data/fields/GF(36893488147419103183)/poly_evaluate.pkl and b/tests/data/fields/GF(36893488147419103183)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(36893488147419103183)/poly_power.pkl b/tests/data/fields/GF(36893488147419103183)/poly_power.pkl index 900dea0b0..9df500591 100644 Binary files a/tests/data/fields/GF(36893488147419103183)/poly_power.pkl and b/tests/data/fields/GF(36893488147419103183)/poly_power.pkl differ diff --git a/tests/data/fields/GF(36893488147419103183)/poly_scalar_multiply.pkl b/tests/data/fields/GF(36893488147419103183)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..906e1d7e6 Binary files /dev/null and b/tests/data/fields/GF(36893488147419103183)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(5)/poly_divmod.pkl b/tests/data/fields/GF(5)/poly_divmod.pkl index df15380e2..2102ef7d4 100644 Binary files a/tests/data/fields/GF(5)/poly_divmod.pkl and b/tests/data/fields/GF(5)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(5)/poly_evaluate.pkl b/tests/data/fields/GF(5)/poly_evaluate.pkl index 7eae51f92..25e1730bc 100644 Binary files a/tests/data/fields/GF(5)/poly_evaluate.pkl and b/tests/data/fields/GF(5)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(5)/poly_power.pkl b/tests/data/fields/GF(5)/poly_power.pkl index a8ea844fc..41f0651e2 100644 Binary files a/tests/data/fields/GF(5)/poly_power.pkl and b/tests/data/fields/GF(5)/poly_power.pkl differ diff --git a/tests/data/fields/GF(5)/poly_scalar_multiply.pkl b/tests/data/fields/GF(5)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..06cd0d79d Binary files /dev/null and b/tests/data/fields/GF(5)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(7)/poly_divmod.pkl b/tests/data/fields/GF(7)/poly_divmod.pkl index fbab821ba..446e78028 100644 Binary files a/tests/data/fields/GF(7)/poly_divmod.pkl and b/tests/data/fields/GF(7)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(7)/poly_evaluate.pkl b/tests/data/fields/GF(7)/poly_evaluate.pkl index ec5791ae0..cf23b3e16 100644 Binary files a/tests/data/fields/GF(7)/poly_evaluate.pkl and b/tests/data/fields/GF(7)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(7)/poly_power.pkl b/tests/data/fields/GF(7)/poly_power.pkl index a79bba4e2..3864fbff2 100644 Binary files a/tests/data/fields/GF(7)/poly_power.pkl and b/tests/data/fields/GF(7)/poly_power.pkl differ diff --git a/tests/data/fields/GF(7)/poly_scalar_multiply.pkl b/tests/data/fields/GF(7)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..772bc4b9d Binary files /dev/null and b/tests/data/fields/GF(7)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(7^3)/poly_divmod.pkl b/tests/data/fields/GF(7^3)/poly_divmod.pkl index 332ba86fa..63c9242e7 100644 Binary files a/tests/data/fields/GF(7^3)/poly_divmod.pkl and b/tests/data/fields/GF(7^3)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(7^3)/poly_evaluate.pkl b/tests/data/fields/GF(7^3)/poly_evaluate.pkl index 8dc63446f..ee3854e20 100644 Binary files a/tests/data/fields/GF(7^3)/poly_evaluate.pkl and b/tests/data/fields/GF(7^3)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(7^3)/poly_power.pkl b/tests/data/fields/GF(7^3)/poly_power.pkl index 9a85e110b..7ed673b2e 100644 Binary files a/tests/data/fields/GF(7^3)/poly_power.pkl and b/tests/data/fields/GF(7^3)/poly_power.pkl differ diff --git a/tests/data/fields/GF(7^3)/poly_scalar_multiply.pkl b/tests/data/fields/GF(7^3)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..67566f7b7 Binary files /dev/null and b/tests/data/fields/GF(7^3)/poly_scalar_multiply.pkl differ diff --git a/tests/data/fields/GF(7^3, 643, 244)/poly_divmod.pkl b/tests/data/fields/GF(7^3, 643, 244)/poly_divmod.pkl index 917a9354b..e3a8a1ee4 100644 Binary files a/tests/data/fields/GF(7^3, 643, 244)/poly_divmod.pkl and b/tests/data/fields/GF(7^3, 643, 244)/poly_divmod.pkl differ diff --git a/tests/data/fields/GF(7^3, 643, 244)/poly_evaluate.pkl b/tests/data/fields/GF(7^3, 643, 244)/poly_evaluate.pkl index 6aa74c761..b1c61e9d4 100644 Binary files a/tests/data/fields/GF(7^3, 643, 244)/poly_evaluate.pkl and b/tests/data/fields/GF(7^3, 643, 244)/poly_evaluate.pkl differ diff --git a/tests/data/fields/GF(7^3, 643, 244)/poly_power.pkl b/tests/data/fields/GF(7^3, 643, 244)/poly_power.pkl index fa9ae6b83..d7a9d9f14 100644 Binary files a/tests/data/fields/GF(7^3, 643, 244)/poly_power.pkl and b/tests/data/fields/GF(7^3, 643, 244)/poly_power.pkl differ diff --git a/tests/data/fields/GF(7^3, 643, 244)/poly_scalar_multiply.pkl b/tests/data/fields/GF(7^3, 643, 244)/poly_scalar_multiply.pkl new file mode 100644 index 000000000..a2a1f896e Binary files /dev/null and b/tests/data/fields/GF(7^3, 643, 244)/poly_scalar_multiply.pkl differ diff --git a/tests/polys/conftest.py b/tests/polys/conftest.py index 9136cf240..f425ffdf5 100644 --- a/tests/polys/conftest.py +++ b/tests/polys/conftest.py @@ -26,19 +26,53 @@ def load_poly_luts(name, GF, folder): @pytest.fixture(scope="session") def poly_add(field_folder): GF, folder = field_folder - return load_poly_luts("poly_add.pkl", GF, folder) + with open(os.path.join(folder, "poly_add.pkl"), "rb") as f: + print(f"Loading {f}...") + d = pickle.load(f) + d["GF"] = GF + d["X"] = [galois.Poly(p, field=GF) for p in d["X"]] + d["Y"] = [galois.Poly(p, field=GF) for p in d["Y"]] + d["Z"] = [galois.Poly(p, field=GF) for p in d["Z"]] + return d @pytest.fixture(scope="session") def poly_subtract(field_folder): GF, folder = field_folder - return load_poly_luts("poly_subtract.pkl", GF, folder) + with open(os.path.join(folder, "poly_subtract.pkl"), "rb") as f: + print(f"Loading {f}...") + d = pickle.load(f) + d["GF"] = GF + d["X"] = [galois.Poly(p, field=GF) for p in d["X"]] + d["Y"] = [galois.Poly(p, field=GF) for p in d["Y"]] + d["Z"] = [galois.Poly(p, field=GF) for p in d["Z"]] + return d @pytest.fixture(scope="session") def poly_multiply(field_folder): GF, folder = field_folder - return load_poly_luts("poly_multiply.pkl", GF, folder) + with open(os.path.join(folder, "poly_multiply.pkl"), "rb") as f: + print(f"Loading {f}...") + d = pickle.load(f) + d["GF"] = GF + d["X"] = [galois.Poly(p, field=GF) for p in d["X"]] + d["Y"] = [galois.Poly(p, field=GF) for p in d["Y"]] + d["Z"] = [galois.Poly(p, field=GF) for p in d["Z"]] + return d + + +@pytest.fixture(scope="session") +def poly_scalar_multiply(field_folder): + GF, folder = field_folder + with open(os.path.join(folder, "poly_scalar_multiply.pkl"), "rb") as f: + print(f"Loading {f}...") + d = pickle.load(f) + d["GF"] = GF + d["X"] = [galois.Poly(p, field=GF) for p in d["X"]] + d["Y"] = d["Y"] + d["Z"] = [galois.Poly(p, field=GF) for p in d["Z"]] + return d @pytest.fixture(scope="session") diff --git a/tests/polys/test_arithmetic.py b/tests/polys/test_arithmetic.py index 0137ca357..7d6d82670 100644 --- a/tests/polys/test_arithmetic.py +++ b/tests/polys/test_arithmetic.py @@ -46,6 +46,25 @@ def test_multiply(poly_multiply): assert type(z.coeffs) is GF +def test_scalar_multiply(poly_scalar_multiply): + GF, X, Y, Z = poly_scalar_multiply["GF"], poly_scalar_multiply["X"], poly_scalar_multiply["Y"], poly_scalar_multiply["Z"] + for i in range(len(X)): + x = X[i] + y = Y[i] + + z = x * y + assert z == Z[i] + assert isinstance(z, galois.Poly) + assert z.field is GF + assert type(z.coeffs) is GF + + z = y * x + assert z == Z[i] + assert isinstance(z, galois.Poly) + assert z.field is GF + assert type(z.coeffs) is GF + + def test_divmod(poly_divmod): GF, X, Y, Q, R = poly_divmod["GF"], poly_divmod["X"], poly_divmod["Y"], poly_divmod["Q"], poly_divmod["R"] for i in range(len(X)): diff --git a/tests/polys/test_non_poly_arithmetic.py b/tests/polys/test_non_poly_arithmetic.py index 59d5f9d21..6fa274cf9 100644 --- a/tests/polys/test_non_poly_arithmetic.py +++ b/tests/polys/test_non_poly_arithmetic.py @@ -59,12 +59,6 @@ def test_multiply(): assert poly * e == poly * e_poly assert e * poly == e_poly * poly - # Not a Galois field array - with pytest.raises(TypeError): - poly * 1 - with pytest.raises(TypeError): - 1 * poly - # Not a 0-D Galois field array with pytest.raises(ValueError): poly * GF.Random(3, low=1)