@@ -66,6 +66,8 @@ from cypari2.stack cimport clear_stack
66
66
67
67
from sage.structure.parent cimport Parent
68
68
from sage.structure.element cimport Vector
69
+ from sage.rings.fast_arith cimport arith_int
70
+ cdef arith_int ai = arith_int()
69
71
70
72
from sage.interfaces.abc import GapElement
71
73
@@ -837,6 +839,19 @@ cdef class FiniteField_givaro_iterator:
837
839
cdef class FiniteField_givaroElement(FinitePolyExtElement):
838
840
"""
839
841
An element of a (Givaro) finite field.
842
+
843
+ Internal implementation detail: ``self.element`` is a ``cdef int`` member such that:
844
+
845
+ - if ``self.element == 0``, then ``self.is_zero()``,
846
+
847
+ - otherwise, ``self == g^self.element`` where ``g`` is a multiplicative generator.
848
+
849
+ In Givaro code, the type of ``element`` is known by the typename ``Rep``.
850
+
851
+ It is preferred to use the exposed interface of Givaro than to rely on this implementation detail.
852
+
853
+ The C function :func:`make_FiniteField_givaroElement` can be internally used to construct a
854
+ :func:`FiniteField_givaroElement` object given ``int element``.
840
855
"""
841
856
842
857
def __init__ (FiniteField_givaroElement self , parent ):
@@ -1036,7 +1051,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1036
1051
sage: k(3).sqrt()
1037
1052
Traceback (most recent call last):
1038
1053
...
1039
- ValueError: must be a perfect square.
1054
+ ValueError: must be a perfect square
1040
1055
1041
1056
TESTS::
1042
1057
@@ -1066,9 +1081,9 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1066
1081
elif cache.objectptr.characteristic() == 2 :
1067
1082
return make_FiniteField_givaroElement(cache, (cache.objectptr.cardinality() - 1 + self .element) / 2 )
1068
1083
elif extend:
1069
- raise NotImplementedError # TODO: fix this once we have nested embeddings of finite fields
1084
+ raise NotImplementedError # TODO: use RingExtension or GF(p^(2*e))
1070
1085
else :
1071
- raise ValueError (" must be a perfect square. " )
1086
+ raise ValueError (" must be a perfect square" )
1072
1087
1073
1088
cpdef _add_(self , right):
1074
1089
"""
@@ -1227,6 +1242,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1227
1242
1228
1243
ALGORITHM:
1229
1244
1245
+ Makes use of the internal representation of Givaro objects.
1230
1246
Givaro objects are stored as integers `i` such that ``self`` `= a^ i`,
1231
1247
where `a` is a generator of `K` ( though not necessarily the one
1232
1248
returned by ``K. gens( ) ``) . Now it is trivial to compute
@@ -1244,23 +1260,24 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1244
1260
exp = _exp
1245
1261
1246
1262
cdef Cache_givaro cache = self ._cache
1263
+ cdef GivaroGfq * objectptr = cache.objectptr
1247
1264
1248
- if (cache. objectptr) .isOne(self .element):
1265
+ if objectptr.isOne(self .element):
1249
1266
return self
1250
1267
1251
1268
elif exp == 0 :
1252
- return make_FiniteField_givaroElement(cache, cache. objectptr.one)
1269
+ return make_FiniteField_givaroElement(cache, objectptr.one)
1253
1270
1254
- elif (cache. objectptr) .isZero(self .element):
1271
+ elif objectptr.isZero(self .element):
1255
1272
if exp < 0 :
1256
1273
raise ZeroDivisionError (' division by zero in finite field' )
1257
- return make_FiniteField_givaroElement(cache, cache. objectptr.zero)
1274
+ return make_FiniteField_givaroElement(cache, objectptr.zero)
1258
1275
1259
- cdef int order = ( cache.order_c() - 1 )
1276
+ cdef int order = cache.order_c() - 1
1260
1277
cdef int r = exp % order
1261
1278
1262
1279
if r == 0 :
1263
- return make_FiniteField_givaroElement(cache, cache. objectptr.one)
1280
+ return make_FiniteField_givaroElement(cache, objectptr.one)
1264
1281
1265
1282
cdef unsigned int r_unsigned
1266
1283
if r < 0 :
@@ -1271,12 +1288,12 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1271
1288
cdef unsigned int order_unsigned = < unsigned int > order
1272
1289
r = < int > (r_unsigned * elt_unsigned) % order_unsigned
1273
1290
if r == 0 :
1274
- return make_FiniteField_givaroElement(cache, cache. objectptr.one)
1291
+ return make_FiniteField_givaroElement(cache, objectptr.one)
1275
1292
return make_FiniteField_givaroElement(cache, r)
1276
1293
1277
1294
cpdef _richcmp_(left, right, int op):
1278
1295
"""
1279
- Comparison of finite field elements is correct or equality
1296
+ Comparison of finite field elements is correct for equality
1280
1297
tests and somewhat random for ``<`` and ``>`` type of
1281
1298
comparisons. This implementation performs these tests by
1282
1299
comparing the underlying int representations.
@@ -1342,7 +1359,8 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1342
1359
1343
1360
.. SEEALSO::
1344
1361
1345
- :meth:`sage. rings. finite_rings. element_base. FinitePolyExtElement. to_integer`
1362
+ - :meth:`sage. rings. finite_rings. element_base. FinitePolyExtElement. to_integer`
1363
+ - :meth:`_log_to_int`, identical to this method but returns a Sage :class:`~sage. rings. integer. Integer`.
1346
1364
1347
1365
EXAMPLES::
1348
1366
@@ -1372,7 +1390,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1372
1390
...
1373
1391
TypeError: not in prime subfield
1374
1392
"""
1375
- cdef int a = self ._cache.log_to_int(self .element)
1393
+ cdef unsigned int a = self ._cache.log_to_int(self .element)
1376
1394
if a < self ._cache.objectptr.characteristic():
1377
1395
return Integer(a)
1378
1396
raise TypeError (" not in prime subfield" )
@@ -1386,6 +1404,10 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1386
1404
`e = a_0 + a_1x + a_2x^ 2 + \c dots`, the int representation is
1387
1405
`a_0 + a_1 p + a_2 p^ 2 + \c dots`.
1388
1406
1407
+ .. SEEALSO::
1408
+
1409
+ - :meth:`_integer_representation`, identical to this method but returns a Python ``int``.
1410
+
1389
1411
EXAMPLES::
1390
1412
1391
1413
sage: k. <b> = GF( 5^ 2) ; k
@@ -1411,35 +1433,25 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1411
1433
- ``check`` -- boolean (default: ``False``): If set,
1412
1434
test whether the given ``order`` is correct.
1413
1435
1414
- .. WARNING::
1415
-
1416
- TODO -- This is currently implemented by solving the discrete
1417
- log problem -- which shouldn't be needed because of how finite field
1418
- elements are represented.
1419
-
1420
1436
EXAMPLES::
1421
1437
1422
1438
sage: k.<b> = GF(5^2); k
1423
1439
Finite Field in b of size 5^2
1424
1440
sage: a = b^7
1425
1441
sage: a.log(b)
1426
1442
7
1427
-
1428
- TESTS:
1429
-
1430
- An example for ``check=True``::
1431
-
1432
- sage: F.<t> = GF(3^5, impl='givaro')
1433
- sage: t.log(t, 3^4, check=True)
1434
- Traceback (most recent call last):
1435
- ...
1436
- ValueError: 81 is not a multiple of the order of the base
1437
1443
"""
1438
- b = self .parent()(base)
1444
+ cdef FiniteField_givaroElement b = self .parent()(base)
1445
+ if b.is_zero():
1446
+ raise ValueError
1439
1447
if (order is not None ) and check and not (b** order).is_one():
1440
1448
raise ValueError (f" {order} is not a multiple of the order of the base" )
1441
-
1442
- return sage.groups.generic.discrete_log(self , b, ord = order)
1449
+ cdef int multiplicative_group_order = self ._cache.order_c() - 1
1450
+ cdef int gcd_b = ai.c_gcd_int(multiplicative_group_order, b.element)
1451
+ if self .element % gcd_b != 0 :
1452
+ raise ValueError (' no logarithm exists' )
1453
+ cdef int b_order = multiplicative_group_order / gcd_b
1454
+ return self .element / gcd_b * < long long > ai.c_inverse_mod_int(b.element / gcd_b, b_order) % b_order
1443
1455
1444
1456
def _int_repr (FiniteField_givaroElement self ):
1445
1457
r """
@@ -1570,25 +1582,9 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
1570
1582
sage: (b^6).multiplicative_order()
1571
1583
4
1572
1584
"""
1573
- # TODO -- I'm sure this can be made vastly faster
1574
- # using how elements are represented as a power of the generator ??
1575
-
1576
- if self ._multiplicative_order is not None :
1577
- return self ._multiplicative_order
1578
- else :
1579
- if self .is_zero():
1580
- raise ArithmeticError (" Multiplicative order of 0 not defined." )
1581
- n = (self ._cache).order_c() - 1
1582
- order = Integer(1 )
1583
- for p, e in sage.arith.misc.factor(n):
1584
- # Determine the power of p that divides the order.
1585
- a = self ** (n / (p** e))
1586
- while a != 1 :
1587
- order = order * p
1588
- a = a** p
1589
-
1590
- self ._multiplicative_order = order
1591
- return order
1585
+ if self .is_zero():
1586
+ raise ArithmeticError (" multiplicative order of 0 not defined" )
1587
+ return Integer((self ._cache.order_c() - 1 ) / ai.c_gcd_int(self .element, self ._cache.order_c() - 1 ))
1592
1588
1593
1589
def __copy__ (self ):
1594
1590
"""
0 commit comments