@@ -66,6 +66,8 @@ from cypari2.stack cimport clear_stack
6666
6767from sage.structure.parent cimport Parent
6868from sage.structure.element cimport Vector
69+ from sage.rings.fast_arith cimport arith_int
70+ cdef arith_int ai = arith_int()
6971
7072from sage.interfaces.abc import GapElement
7173
@@ -837,6 +839,19 @@ cdef class FiniteField_givaro_iterator:
837839cdef class FiniteField_givaroElement(FinitePolyExtElement):
838840 """
839841 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``.
840855 """
841856
842857 def __init__ (FiniteField_givaroElement self , parent ):
@@ -1036,7 +1051,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
10361051 sage: k(3).sqrt()
10371052 Traceback (most recent call last):
10381053 ...
1039- ValueError: must be a perfect square.
1054+ ValueError: must be a perfect square
10401055
10411056 TESTS::
10421057
@@ -1066,9 +1081,9 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
10661081 elif cache.objectptr.characteristic() == 2 :
10671082 return make_FiniteField_givaroElement(cache, (cache.objectptr.cardinality() - 1 + self .element) / 2 )
10681083 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))
10701085 else :
1071- raise ValueError (" must be a perfect square. " )
1086+ raise ValueError (" must be a perfect square" )
10721087
10731088 cpdef _add_(self , right):
10741089 """
@@ -1227,6 +1242,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
12271242
12281243 ALGORITHM:
12291244
1245+ Makes use of the internal representation of Givaro objects.
12301246 Givaro objects are stored as integers `i` such that ``self`` `= a^ i`,
12311247 where `a` is a generator of `K` ( though not necessarily the one
12321248 returned by ``K. gens( ) ``) . Now it is trivial to compute
@@ -1244,23 +1260,24 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
12441260 exp = _exp
12451261
12461262 cdef Cache_givaro cache = self ._cache
1263+ cdef GivaroGfq * objectptr = cache.objectptr
12471264
1248- if (cache. objectptr) .isOne(self .element):
1265+ if objectptr.isOne(self .element):
12491266 return self
12501267
12511268 elif exp == 0 :
1252- return make_FiniteField_givaroElement(cache, cache. objectptr.one)
1269+ return make_FiniteField_givaroElement(cache, objectptr.one)
12531270
1254- elif (cache. objectptr) .isZero(self .element):
1271+ elif objectptr.isZero(self .element):
12551272 if exp < 0 :
12561273 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)
12581275
1259- cdef int order = ( cache.order_c() - 1 )
1276+ cdef int order = cache.order_c() - 1
12601277 cdef int r = exp % order
12611278
12621279 if r == 0 :
1263- return make_FiniteField_givaroElement(cache, cache. objectptr.one)
1280+ return make_FiniteField_givaroElement(cache, objectptr.one)
12641281
12651282 cdef unsigned int r_unsigned
12661283 if r < 0 :
@@ -1271,12 +1288,12 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
12711288 cdef unsigned int order_unsigned = < unsigned int > order
12721289 r = < int > (r_unsigned * elt_unsigned) % order_unsigned
12731290 if r == 0 :
1274- return make_FiniteField_givaroElement(cache, cache. objectptr.one)
1291+ return make_FiniteField_givaroElement(cache, objectptr.one)
12751292 return make_FiniteField_givaroElement(cache, r)
12761293
12771294 cpdef _richcmp_(left, right, int op):
12781295 """
1279- Comparison of finite field elements is correct or equality
1296+ Comparison of finite field elements is correct for equality
12801297 tests and somewhat random for ``<`` and ``>`` type of
12811298 comparisons. This implementation performs these tests by
12821299 comparing the underlying int representations.
@@ -1342,7 +1359,8 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
13421359
13431360 .. SEEALSO::
13441361
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`.
13461364
13471365 EXAMPLES::
13481366
@@ -1372,7 +1390,7 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
13721390 ...
13731391 TypeError: not in prime subfield
13741392 """
1375- cdef int a = self ._cache.log_to_int(self .element)
1393+ cdef unsigned int a = self ._cache.log_to_int(self .element)
13761394 if a < self ._cache.objectptr.characteristic():
13771395 return Integer(a)
13781396 raise TypeError (" not in prime subfield" )
@@ -1386,6 +1404,10 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
13861404 `e = a_0 + a_1x + a_2x^ 2 + \c dots`, the int representation is
13871405 `a_0 + a_1 p + a_2 p^ 2 + \c dots`.
13881406
1407+ .. SEEALSO::
1408+
1409+ - :meth:`_integer_representation`, identical to this method but returns a Python ``int``.
1410+
13891411 EXAMPLES::
13901412
13911413 sage: k. <b> = GF( 5^ 2) ; k
@@ -1411,35 +1433,25 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
14111433 - ``check`` -- boolean (default: ``False``): If set,
14121434 test whether the given ``order`` is correct.
14131435
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-
14201436 EXAMPLES::
14211437
14221438 sage: k.<b> = GF(5^2); k
14231439 Finite Field in b of size 5^2
14241440 sage: a = b^7
14251441 sage: a.log(b)
14261442 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
14371443 """
1438- b = self .parent()(base)
1444+ cdef FiniteField_givaroElement b = self .parent()(base)
1445+ if b.is_zero():
1446+ raise ValueError
14391447 if (order is not None ) and check and not (b** order).is_one():
14401448 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
14431455
14441456 def _int_repr (FiniteField_givaroElement self ):
14451457 r """
@@ -1570,25 +1582,9 @@ cdef class FiniteField_givaroElement(FinitePolyExtElement):
15701582 sage: (b^6).multiplicative_order()
15711583 4
15721584 """
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 ))
15921588
15931589 def __copy__ (self ):
15941590 """
0 commit comments