Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Algebraic closures of finite fields
Let `\Bold{F}` be a finite field, and let `\overline{\Bold{F}}` be an algebraic closure of `\Bold{F}`; this is unique up to (non-canonical) isomorphism. For every `n\ge 1`, there is a unique subfield `\Bold{F}_n` of `\overline{\Bold{F}}` such that `\Bold{F}\subset\Bold{F}_n` and `[\Bold{F}_n:\Bold{F}]=n`.
In Sage, algebraic closures of finite fields are implemented using compatible systems of finite fields. The resulting Sage object keeps track of a finite lattice of the subfields `\Bold{F}_n` and the embeddings between them. This lattice is extended as necessary.
The Sage class corresponding to `\overline{\Bold{F}}` can be constructed from the finite field `\Bold{F}` by using the :meth:`~sage.rings.finite_rings.finite_field_base.FiniteField.algebraic_closure` method.
The Sage class for elements of `\overline{\Bold{F}}` is :class:`AlgebraicClosureFiniteFieldElement`. Such an element is represented as an element of one of the `\Bold{F}_n`. This means that each element `x\in\Bold{F}` has infinitely many different representations, one for each `n` such that `x` is in `\Bold{F}_n`.
.. NOTE::
Only prime finite fields are currently accepted as base fields for algebraic closures. To obtain an algebraic closure of a non-prime finite field `\Bold{F}`, take an algebraic closure of the prime field of `\Bold{F}` and embed `\Bold{F}` into this.
Algebraic closures of finite fields are currently implemented using (pseudo-)Conway polynomials; see :class:`AlgebraicClosureFiniteField_pseudo_conway` and the module :mod:`~sage.rings.finite_rings.conway_polynomials`. Other implementations may be added by creating appropriate subclasses of :class:`AlgebraicClosureFiniteField_generic`.
In the current implementation, algebraic closures do not satisfy the unique parent condition. Moreover, there is no coercion map between different algebraic closures of the same finite field. There is a conceptual reason for this, namely that the definition of pseudo-Conway polynomials only determines an algebraic closure up to *non-unique* isomorphism. This means in particular that different algebraic closures, and their respective elements, never compare equal.
AUTHORS:
- Peter Bruin (August 2013): initial version
- Vincent Delecroix (November 2013): additional methods
"""
""" Element of an algebraic closure of a finite field.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2) z2 sage: type(F.gen(2)) <class 'sage.rings.algebraic_closure_finite_field.AlgebraicClosureFiniteField_pseudo_conway_with_category.element_class'>
""" """ TESTS::
sage: F = GF(3).algebraic_closure() sage: TestSuite(F.gen(2)).run(skip=['_test_pickling'])
.. NOTE::
The ``_test_pickling`` test has to be skipped because there is no coercion map between the parents of ``x`` and ``loads(dumps(x))``.
""" else:
r""" TESTS::
sage: F = GF(2).algebraic_closure() sage: hash(F.zero()) 0 sage: hash(F.one()) 1 sage: z1 = F.gen(1) sage: z2 = F.gen(2) sage: z3 = F.gen(3) sage: z4 = F.gen(4)
sage: hash(z2) == hash(z3+z2-z3) True sage: hash(F.zero()) == hash(z3+z2-z3-z2) True
sage: X = [z4**i for i in range(2**4-1)] sage: X.append(F.zero()) sage: X.extend([z3, z3**2, z3*z4]) sage: assert len(X) == len(set(hash(x) for x in X))
sage: F = GF(3).algebraic_closure() sage: z1 = F.gen(1) sage: z2 = F.gen(2) sage: z3 = F.gen(3) sage: z4 = F.gen(4)
sage: hash(z2) == hash(z3+z2-z3) True
sage: X = [z4**i for i in range(3**4-1)] sage: X.append(F.zero()) sage: X.extend([z3, z3**2, z3*z4]) sage: assert len(X) == len(set(hash(x) for x in X))
Check that :trac:`19956` is fixed::
sage: R.<x,y> = GF(2).algebraic_closure()[] sage: x.resultant(y) -y """ #TODO: this is *very* slow #NOTE: the hash of a generator (e.g. z2, z3, ...) is always the # characterisitc! In particular its hash value is not compatible with # sections.
""" Return a string representation of ``self``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F._repr_() 'Algebraic closure of Finite Field of size 3'
"""
""" Compare ``self`` with ``right``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2) == F.gen(3) False """
r""" TESTS::
sage: F2 = GF(2).algebraic_closure() sage: z12 = F2.gen(3*4) sage: z12**3 z12^3 sage: z12**13 z12^8 + z12^7 + z12^6 + z12^4 + z12^2 + z12 """
""" Return ``self`` + ``right``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2) + F.gen(3) z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 1
"""
""" Return ``self`` - ``right``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2) - F.gen(3) z6^4 + 2*z6^3 + z6^2 + 2*z6
"""
""" Return ``self`` * ``right``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2) * F.gen(3) z6^5 + 2*z6^4 + z6^2 + 2
"""
""" Return ``self`` / ``right``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2) / F.gen(3) z6^5 + 2*z6^4 + z6^3 + 1
"""
""" Return a representation of ``self`` as an element of the subfield of degree `n` of the parent, if possible.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: z = F.gen(4) sage: (z^10).change_level(6) 2*z6^5 + 2*z6^3 + z6^2 + 2*z6 + 2 sage: z.change_level(6) Traceback (most recent call last): ... ValueError: z4 is not in the image of Ring morphism: From: Finite Field in z2 of size 3^2 To: Finite Field in z4 of size 3^4 Defn: z2 |--> 2*z4^3 + 2*z4^2 + 1
sage: a = F(1).change_level(3); a 1 sage: a.change_level(2) 1 sage: F.gen(3).change_level(1) Traceback (most recent call last): ... ValueError: z3 is not in the image of Ring morphism: From: Finite Field of size 3 To: Finite Field in z3 of size 3^3 Defn: 1 |--> 1
"""
""" Return a LaTeX representation of ``self``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: s = F.gen(1) + F.gen(2) + F.gen(3) sage: s z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 2 sage: latex(s) z_{6}^{5} + 2 z_{6}^{4} + 2 z_{6}^{3} + z_{6}^{2} + 2 z_{6} + 2
"""
""" Return the minimal polynomial of ``self`` over the prime field.
EXAMPLES::
sage: F = GF(11).algebraic_closure() sage: F.gen(3).minpoly() x^3 + 2*x + 9
"""
""" Return ``True`` if ``self`` is a square.
This always returns ``True``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2).is_square() True
"""
""" Return a square root of ``self``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.gen(2).sqrt() z4^3 + z4 + 1
""" return self.__class__(F, x.sqrt(extend=False)) else:
""" Return an `n`-th root of ``self``.
EXAMPLES::
sage: F = GF(5).algebraic_closure() sage: t = F.gen(2) + 1 sage: s = t.nth_root(15); s 4*z6^5 + 3*z6^4 + 2*z6^3 + 2*z6^2 + 4 sage: s**15 == t True
.. TODO::
This function could probably be made faster.
""" # In order to be smart we look for the smallest subfield that # actually contains the root.
raise AssertionError('cannot find n-th root in algebraic closure of finite field')
""" Return the multiplicative order of ``self``.
EXAMPLES::
sage: K = GF(7).algebraic_closure() sage: K.gen(5).multiplicative_order() 16806 sage: (K.gen(1) + K.gen(2) + K.gen(3)).multiplicative_order() 7353
"""
""" Return the `p^k`-th power of ``self``, where `p` is the characteristic of ``self.parent()``.
EXAMPLES::
sage: K = GF(13).algebraic_closure('t') sage: t3 = K.gen(3) sage: s = 1 + t3 + t3**2 sage: s.pth_power() 10*t3^2 + 6*t3 sage: s.pth_power(2) 2*t3^2 + 6*t3 + 11 sage: s.pth_power(3) t3^2 + t3 + 1 sage: s.pth_power(3).parent() is K True
"""
""" Return the unique `p^k`-th root of ``self``, where `p` is the characteristic of ``self.parent()``.
EXAMPLES::
sage: K = GF(13).algebraic_closure('t') sage: t3 = K.gen(3) sage: s = 1 + t3 + t3**2 sage: s.pth_root() 2*t3^2 + 6*t3 + 11 sage: s.pth_root(2) 10*t3^2 + 6*t3 sage: s.pth_root(3) t3^2 + t3 + 1 sage: s.pth_root(2).parent() is K True
"""
""" Return ``self`` as a finite field element.
INPUT:
- ``minimal`` -- boolean (default: ``False``). If ``True``, always return the smallest subfield containing ``self``.
OUTPUT:
- a triple (``field``, ``element``, ``morphism``) where ``field`` is a finite field, ``element`` an element of ``field`` and ``morphism`` a morphism from ``field`` to ``self.parent()``.
EXAMPLES::
sage: F = GF(3).algebraic_closure('t') sage: t = F.gen(5) sage: t.as_finite_field_element() (Finite Field in t5 of size 3^5, t5, Ring morphism: From: Finite Field in t5 of size 3^5 To: Algebraic closure of Finite Field of size 3 Defn: t5 |--> t5)
By default, ``field`` is not necessarily minimal. We can force it to be minimal using the ``minimal`` option::
sage: s = t + 1 - t sage: s.as_finite_field_element()[0] Finite Field in t5 of size 3^5 sage: s.as_finite_field_element(minimal=True)[0] Finite Field of size 3
This also works when the element has to be converted between two non-trivial finite subfields (see :trac:`16509`)::
sage: K = GF(5).algebraic_closure() sage: z = K.gen(5) - K.gen(5) + K.gen(2) sage: z.as_finite_field_element(minimal=True) (Finite Field in z2 of size 5^2, z2, Ring morphism: From: Finite Field in z2 of size 5^2 To: Algebraic closure of Finite Field of size 5 Defn: z2 |--> z2)
There is currently no automatic conversion between the various subfields::
sage: a = K.gen(2) + 1 sage: _,b,_ = a.as_finite_field_element() sage: K4 = K.subfield(4)[0] sage: K4(b) Traceback (most recent call last): ... TypeError: unable to coerce from a finite field other than the prime subfield
Nevertheless it is possible to use the inclusions that are implemented at the level of the algebraic closure::
sage: f = K.inclusion(2,4); f Ring morphism: From: Finite Field in z2 of size 5^2 To: Finite Field in z4 of size 5^4 Defn: z2 |--> z4^3 + z4^2 + z4 + 3 sage: f(b) z4^3 + z4^2 + z4 + 4
"""
else:
""" Algebraic closure of a finite field.
""" """ TESTS::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic sage: F = AlgebraicClosureFiniteField_generic(GF(5), 'z') sage: F Algebraic closure of Finite Field of size 5
""" normalize=False, category=category)
""" Compare ``self`` with ``other``.
TESTS::
sage: F3 = GF(3).algebraic_closure() sage: F3 == F3 True sage: F5 = GF(5).algebraic_closure() sage: F3 == F5 False """ if self is other: return True if type(self) != type(other): return False return ((self.base_ring(), self.variable_name(), self.category()) == (other.base_ring(), other.variable_name(), other.category()))
""" Check whether ``self`` and ``other`` are not equal.
TESTS::
sage: F3 = GF(3).algebraic_closure() sage: F3 != F3 False sage: F5 = GF(5).algebraic_closure() sage: F3 != F5 True """ return not (self == other)
""" Return the cardinality of ``self``.
This always returns ``+Infinity``.
.. TODO::
When :trac:`10963` is merged we should remove that method and set the category to infinite fields (i.e. ``Fields().Infinite()``).
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.cardinality() +Infinity
"""
""" Returns ``False`` as an algebraically closed field is always infinite.
.. TODO::
When :trac:`10963` is merged we should remove that method and set the category to infinite fields (i.e. ``Fields().Infinite()``).
EXAMPLES::
sage: GF(3).algebraic_closure().is_finite() False
"""
""" Return the characteristic of ``self``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: p = next_prime(1000) sage: F = AlgebraicClosureFiniteField(GF(p), 'z') sage: F.characteristic() == p True
"""
""" Construct an element of ``self``.
TESTS::
sage: F = GF(5).algebraic_closure() sage: type(F(3)) <class 'sage.rings.algebraic_closure_finite_field.AlgebraicClosureFiniteField_pseudo_conway_with_category.element_class'>
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F1 = AlgebraicClosureFiniteField(GF(3), 'z') sage: F2 = AlgebraicClosureFiniteField(GF(3), 'z') sage: F1(F2.gen(1)) Traceback (most recent call last): ... ValueError: no conversion defined between different algebraic closures
""" return x else:
""" Return ``True`` if elements of ``other`` can be coerced into ``self``.
EXAMPLES::
sage: F = GF(7).algebraic_closure() sage: F.has_coerce_map_from(Integers()) True
""" return True
""" Return a string representation of ``self``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') sage: F._repr_() 'Algebraic closure of Finite Field of size 5'
"""
""" Return a LaTeX representation of ``self``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: latex(F) \overline{\Bold{F}_{3}} """
""" Coerce `x` and `y` to a common subfield of ``self``.
TESTS::
sage: F = GF(3).algebraic_closure() sage: x, y = F._to_common_subfield(F.gen(2), F.gen(3)) sage: x.parent() Finite Field in z6 of size 3^6 sage: y.parent() Finite Field in z6 of size 3^6
"""
def _get_polynomial(self, n): """ Return the polynomial defining the unique subfield of degree `n` of ``self``.
This must be implemented by subclasses.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic sage: F = AlgebraicClosureFiniteField_generic(GF(5), 'z') sage: F._get_polynomial(1) Traceback (most recent call last): ... NotImplementedError: <abstract method _get_polynomial at ...> """
def _get_im_gen(self, m, n): """ Return the image of ``self.gen(m)`` under the canonical inclusion into ``self.subfield(n)``.
This must be implemented by subclasses.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic sage: F = AlgebraicClosureFiniteField_generic(GF(5), 'z') sage: F._get_im_gen(2, 4) Traceback (most recent call last): ... NotImplementedError: <abstract method _get_im_gen at ...>
"""
""" Return the unique subfield of degree `n` of ``self``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F._subfield(4) Finite Field in z4 of size 3^4
""" else: name=self.variable_name() + str(n), modulus=self._get_polynomial(n), check_irreducible=False)
""" Return the unique subfield of degree `n` of ``self`` together with its canonical embedding into ``self``.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.subfield(1) (Finite Field of size 3, Ring morphism: From: Finite Field of size 3 To: Algebraic closure of Finite Field of size 3 Defn: 1 |--> 1) sage: F.subfield(4) (Finite Field in z4 of size 3^4, Ring morphism: From: Finite Field in z4 of size 3^4 To: Algebraic closure of Finite Field of size 3 Defn: z4 |--> z4)
"""
""" Return the canonical inclusion map from the subfield of degree `m` to the subfield of degree `n`.
EXAMPLES::
sage: F = GF(3).algebraic_closure() sage: F.inclusion(1, 2) Ring morphism: From: Finite Field of size 3 To: Finite Field in z2 of size 3^2 Defn: 1 |--> 1 sage: F.inclusion(2, 4) Ring morphism: From: Finite Field in z2 of size 3^2 To: Finite Field in z4 of size 3^4 Defn: z2 |--> 2*z4^3 + 2*z4^2 + 1
""" # check=False is required to avoid "coercion hell": an # infinite loop in checking the morphism involving # polynomial_compiled.pyx on the modulus(). else: raise ValueError("subfield of degree %s not contained in subfield of degree %s" % (m, n))
""" Return the number of generators of ``self``, which is infinity.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: AlgebraicClosureFiniteField(GF(5), 'z').ngens() +Infinity
"""
""" Return the `n`-th generator of ``self``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') sage: F.gen(2) z2
"""
""" Return a family of generators of ``self``.
OUTPUT:
- a :class:`~sage.sets.family.Family`, indexed by the positive integers, whose `n`-th element is ``self.gen(n)``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') sage: g = F.gens() sage: g Lazy family (<lambda>(i))_{i in Positive integers} sage: g[3] z3
"""
""" Return the first `n` generators of ``self``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') sage: F._first_ngens(3) (1, z2, z3)
"""
""" Return an algebraic closure of ``self``.
This always returns ``self``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'z') sage: F.algebraic_closure() is F True
"""
""" TESTS::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = AlgebraicClosureFiniteField(GF(5), 'w') sage: F.an_element() # indirect doctest w2
"""
r""" Return some elements of this field.
EXAMPLES::
sage: F = GF(7).algebraic_closure() sage: F.some_elements() (1, z2, z3 + 1)
"""
r""" Return a list of pairs ``(root,multiplicity)`` of roots of the polynomial ``p``.
If the argument ``multiplicities`` is set to ``False`` then return the list of roots.
.. SEEALSO::
:meth:`_factor_univariate_polynomial`
EXAMPLES::
sage: R.<x> = PolynomialRing(GF(5),'x') sage: K = GF(5).algebraic_closure('t')
sage: sorted((x^6 - 1).roots(K,multiplicities=False)) [1, 4, 2*t2 + 1, 2*t2 + 2, 3*t2 + 3, 3*t2 + 4] sage: ((K.gen(2)*x - K.gen(3))**2).roots(K) [(3*t6^5 + 2*t6^4 + 2*t6^2 + 3, 2)]
sage: for _ in range(10): ....: p = R.random_element(degree=randint(2,8)) ....: for r in p.roots(K, multiplicities=False): ....: assert p(r).is_zero(), "r={} is not a root of p={}".format(r,p)
"""
# first build a polynomial over some finite field
else: # look at the extension of degree g.degree() which contains at # least one root of g # note: there is no coercion from the l-th subfield to the ll-th # subfield. The line below does the conversion manually.
else:
r""" Factorization of univariate polynomials.
EXAMPLES::
sage: K = GF(3).algebraic_closure() sage: R = PolynomialRing(K, 'T') sage: T = R.gen() sage: (K.gen(2) * T^2 - 1).factor() (z2) * (T + z4^3 + z4^2 + z4) * (T + 2*z4^3 + 2*z4^2 + 2*z4)
sage: for d in range(10): ....: p = R.random_element(degree=randint(2,8)) ....: assert p.factor().prod() == p, "error in the factorization of p={}".format(p)
"""
""" Algebraic closure of a finite field, constructed using pseudo-Conway polynomials.
EXAMPLES::
sage: F = GF(5).algebraic_closure(implementation='pseudo_conway') sage: F.cardinality() +Infinity sage: F.algebraic_closure() is F True sage: x = F(3).nth_root(12); x z4^3 + z4^2 + 4*z4 sage: x**12 3
TESTS::
sage: F3 = GF(3).algebraic_closure() sage: F3 == F3 True sage: F5 = GF(5).algebraic_closure() sage: F3 == F5 False
""" """ INPUT:
- ``base_ring`` -- the finite field of which to construct an algebraic closure. Currently only prime fields are accepted.
- ``name`` -- prefix to use for generators of the finite subfields.
- ``category`` -- if provided, specifies the category in which this algebraic closure will be placed.
- ``lattice`` -- :class:`~sage.rings.finite_rings.conway_polynomials.PseudoConwayPolynomialLattice` (default: None). If provided, use this pseudo-Conway polynomial lattice to construct an algebraic closure.
- ``use_database`` -- boolean. If True (default), use actual Conway polynomials whenever they are available in the database. If False, always compute pseudo-Conway polynomials from scratch.
TESTS::
sage: F = GF(5).algebraic_closure(implementation='pseudo_conway') sage: print(F.__class__.__name__) AlgebraicClosureFiniteField_pseudo_conway_with_category sage: TestSuite(F).run(skip=['_test_elements', '_test_pickling'])
sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: L = PseudoConwayLattice(11, use_database=False) sage: F = GF(7).algebraic_closure(lattice=L) Traceback (most recent call last): ... TypeError: lattice must be a pseudo-Conway lattice with characteristic 7 sage: F = GF(11).algebraic_closure(lattice=L) sage: F.gen(2).minimal_polynomial() x^2 + 4*x + 2
sage: F = GF(11).algebraic_closure(use_database=True) sage: F.gen(2).minimal_polynomial() x^2 + 7*x + 2
.. NOTE::
In the test suite, ``_test_pickling`` has to be skipped because ``F`` and ``loads(dumps(F))`` cannot consistently be made to compare equal, and ``_test_elements`` has to be skipped for the reason described in :meth:`AlgebraicClosureFiniteFieldElement.__init__`.
"""
""" Return the defining polynomial of the unique subfield of degree `n` of ``self``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_pseudo_conway sage: F = AlgebraicClosureFiniteField_pseudo_conway(GF(5), 'z') sage: F._get_polynomial(1) x + 3
"""
""" Return the image of ``self.gen(m)`` under the canonical inclusion into ``self.subfield(n)``.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_pseudo_conway sage: F = AlgebraicClosureFiniteField_pseudo_conway(GF(5), 'z') sage: F._get_im_gen(2, 4) z4^3 + z4^2 + z4 + 3
"""
""" Construct an algebraic closure of a finite field.
The recommended way to use this functionality is by calling the :meth:`~sage.rings.finite_rings.finite_field_base.FiniteField.algebraic_closure` method of the finite field.
.. NOTE::
Algebraic closures of finite fields in Sage do not have the unique representation property, because they are not determined up to unique isomorphism by their defining data.
EXAMPLES::
sage: from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField sage: F = GF(2).algebraic_closure() sage: F1 = AlgebraicClosureFiniteField(GF(2), 'z') sage: F1 is F False
In the pseudo-Conway implementation, non-identical instances never compare equal::
sage: F1 == F False sage: loads(dumps(F)) == F False
This is to ensure that the result of comparing two instances cannot change with time.
"""
else: raise ValueError('unknown implementation for algebraic closure of finite field: %s' % implementation) |