| 1 | r""" |
|---|
| 2 | Finite Non-prime Fields of cardinality up to $2^{16}$ |
|---|
| 3 | |
|---|
| 4 | SAGE includes the Givaro finite field library, for highly optimized |
|---|
| 5 | arithmetic in finite fields. |
|---|
| 6 | |
|---|
| 7 | NOTES: The arithmetic is performed by the Givaro C++ library which |
|---|
| 8 | uses Zech logs internally to represent finite field elements. This |
|---|
| 9 | implementation is the default finite extension field implementation in |
|---|
| 10 | SAGE for the cardinality $< 2^{16}$, as it is vastly faster than the |
|---|
| 11 | PARI implementation which uses polynomials to represent finite field |
|---|
| 12 | elements. Some functionality in this class however is implemented |
|---|
| 13 | using the PARI implementation. |
|---|
| 14 | |
|---|
| 15 | EXAMPLES: |
|---|
| 16 | sage: k = GF(5); type(k) |
|---|
| 17 | <class 'sage.rings.finite_field.FiniteField_prime_modn'> |
|---|
| 18 | sage: k = GF(5^2,'c'); type(k) |
|---|
| 19 | <type 'sage.rings.finite_field_givaro.FiniteField_givaro'> |
|---|
| 20 | sage: k = GF(2^16,'c'); type(k) |
|---|
| 21 | <class 'sage.rings.finite_field.FiniteField_ext_pari'> |
|---|
| 22 | |
|---|
| 23 | sage: n = previous_prime_power(2^16 - 1) |
|---|
| 24 | sage: while is_prime(n): |
|---|
| 25 | ... n = previous_prime_power(n) |
|---|
| 26 | sage: factor(n) |
|---|
| 27 | 251^2 |
|---|
| 28 | sage: k = GF(n,'c'); type(k) |
|---|
| 29 | <type 'sage.rings.finite_field_givaro.FiniteField_givaro'> |
|---|
| 30 | |
|---|
| 31 | AUTHORS: |
|---|
| 32 | -- Martin Albrecht <malb@informatik.uni-bremen.de> (2006-06-05) |
|---|
| 33 | -- William Stein (2006-12-07): editing, lots of docs, etc. |
|---|
| 34 | -- Robert Bradshaw (2007-05-23): is_square/sqrt, pow. |
|---|
| 35 | """ |
|---|
| 36 | |
|---|
| 37 | |
|---|
| 38 | #***************************************************************************** |
|---|
| 39 | # |
|---|
| 40 | # SAGE: System for Algebra and Geometry Experimentation |
|---|
| 41 | # |
|---|
| 42 | # Copyright (C) 2006 William Stein <wstein@gmail.com> |
|---|
| 43 | # |
|---|
| 44 | # Distributed under the terms of the GNU General Public License (GPL) |
|---|
| 45 | # |
|---|
| 46 | # This code is distributed in the hope that it will be useful, |
|---|
| 47 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 48 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 49 | # General Public License for more details. |
|---|
| 50 | # |
|---|
| 51 | # The full text of the GPL is available at: |
|---|
| 52 | # |
|---|
| 53 | # http://www.gnu.org/licenses/ |
|---|
| 54 | #***************************************************************************** |
|---|
| 55 | |
|---|
| 56 | include "../ext/interrupt.pxi" |
|---|
| 57 | |
|---|
| 58 | # this fails with a scoping error: |
|---|
| 59 | # AttributeError: CVoidType instance has no attribute 'scope' |
|---|
| 60 | #include "../ext/stdsage.pxi" |
|---|
| 61 | |
|---|
| 62 | cdef extern from "stdsage.h": |
|---|
| 63 | ctypedef void PyObject |
|---|
| 64 | object PY_NEW(object t) |
|---|
| 65 | int PY_TYPE_CHECK(object o, object t) |
|---|
| 66 | void init_csage() |
|---|
| 67 | #init_csage() |
|---|
| 68 | |
|---|
| 69 | from sage.rings.ring cimport FiniteField |
|---|
| 70 | from sage.rings.ring cimport Ring |
|---|
| 71 | from sage.structure.element cimport FiniteFieldElement, Element, RingElement, ModuleElement |
|---|
| 72 | from sage.rings.finite_field_element import FiniteField_ext_pariElement |
|---|
| 73 | from sage.structure.sage_object cimport SageObject |
|---|
| 74 | import operator |
|---|
| 75 | import sage.rings.arith |
|---|
| 76 | import finite_field |
|---|
| 77 | |
|---|
| 78 | import sage.interfaces.gap |
|---|
| 79 | from sage.libs.pari.all import pari |
|---|
| 80 | from sage.libs.pari.gen import gen |
|---|
| 81 | |
|---|
| 82 | from sage.structure.parent cimport Parent |
|---|
| 83 | from sage.structure.parent_base cimport ParentWithBase |
|---|
| 84 | from sage.structure.parent_gens cimport ParentWithGens |
|---|
| 85 | |
|---|
| 86 | |
|---|
| 87 | |
|---|
| 88 | |
|---|
| 89 | |
|---|
| 90 | |
|---|
| 91 | cdef object is_IntegerMod |
|---|
| 92 | cdef object IntegerModRing_generic |
|---|
| 93 | cdef object Integer |
|---|
| 94 | cdef object Rational |
|---|
| 95 | cdef object is_Polynomial |
|---|
| 96 | cdef object ConwayPolynomials |
|---|
| 97 | cdef object conway_polynomial |
|---|
| 98 | cdef object MPolynomial |
|---|
| 99 | cdef object Polynomial |
|---|
| 100 | cdef object FreeModuleElement |
|---|
| 101 | |
|---|
| 102 | cdef void late_import(): |
|---|
| 103 | """ |
|---|
| 104 | """ |
|---|
| 105 | global is_IntegerMod, \ |
|---|
| 106 | IntegerModRing_generic, \ |
|---|
| 107 | Integer, \ |
|---|
| 108 | Rational, \ |
|---|
| 109 | is_Polynomial, \ |
|---|
| 110 | ConwayPolynomials, \ |
|---|
| 111 | conway_polynomial, \ |
|---|
| 112 | MPolynomial, \ |
|---|
| 113 | Polynomial, \ |
|---|
| 114 | FreeModuleElement |
|---|
| 115 | |
|---|
| 116 | if is_IntegerMod is not None: |
|---|
| 117 | return |
|---|
| 118 | |
|---|
| 119 | import sage.rings.integer_mod |
|---|
| 120 | is_IntegerMod = sage.rings.integer_mod.is_IntegerMod |
|---|
| 121 | |
|---|
| 122 | import sage.rings.integer_mod_ring |
|---|
| 123 | IntegerModRing_generic = sage.rings.integer_mod_ring.IntegerModRing_generic |
|---|
| 124 | |
|---|
| 125 | import sage.rings.integer |
|---|
| 126 | Integer = sage.rings.integer.Integer |
|---|
| 127 | |
|---|
| 128 | import sage.rings.rational |
|---|
| 129 | Rational = sage.rings.rational.Rational |
|---|
| 130 | |
|---|
| 131 | import sage.rings.polynomial.polynomial_element |
|---|
| 132 | is_Polynomial = sage.rings.polynomial.polynomial_element.is_Polynomial |
|---|
| 133 | |
|---|
| 134 | import sage.databases.conway |
|---|
| 135 | ConwayPolynomials = sage.databases.conway.ConwayPolynomials |
|---|
| 136 | |
|---|
| 137 | import sage.rings.finite_field |
|---|
| 138 | conway_polynomial = sage.rings.finite_field.conway_polynomial |
|---|
| 139 | |
|---|
| 140 | import sage.rings.polynomial.multi_polynomial_element |
|---|
| 141 | MPolynomial = sage.rings.polynomial.multi_polynomial_element.MPolynomial |
|---|
| 142 | |
|---|
| 143 | import sage.rings.polynomial.polynomial_element |
|---|
| 144 | Polynomial = sage.rings.polynomial.polynomial_element.Polynomial |
|---|
| 145 | |
|---|
| 146 | import sage.modules.free_module_element |
|---|
| 147 | FreeModuleElement = sage.modules.free_module_element.FreeModuleElement |
|---|
| 148 | |
|---|
| 149 | def get_mpol(): |
|---|
| 150 | return MPolynomial |
|---|
| 151 | |
|---|
| 152 | |
|---|
| 153 | cdef FiniteField_givaro parent_object(Element o): |
|---|
| 154 | return <FiniteField_givaro>(o._parent) |
|---|
| 155 | |
|---|
| 156 | cdef class FiniteField_givaro(FiniteField): |
|---|
| 157 | """ |
|---|
| 158 | Fnite Field. These are implemented using Zech logs and the |
|---|
| 159 | cardinality must be < 2^16. See FiniteField_ext_pari for larger |
|---|
| 160 | cardinalities. |
|---|
| 161 | """ |
|---|
| 162 | |
|---|
| 163 | def __init__(FiniteField_givaro self, q, name="a", modulus=None, repr="poly", cache=False): |
|---|
| 164 | """ |
|---|
| 165 | Finite Field. These are implemented using Zech logs and the |
|---|
| 166 | cardinality must be < 2^16. By default conway polynomials are |
|---|
| 167 | used as minimal polynomial. |
|---|
| 168 | |
|---|
| 169 | INPUT: |
|---|
| 170 | q -- p^n (must be prime power) |
|---|
| 171 | name -- variable used for poly_repr (default: 'a') |
|---|
| 172 | modulus -- you may provide a minimal polynomial to use for |
|---|
| 173 | reduction or 'random' to force a random |
|---|
| 174 | irreducible polynomial. (default: None, a conway |
|---|
| 175 | polynomial is used if found. Otherwise a random |
|---|
| 176 | polynomial is used) |
|---|
| 177 | repr -- controls the way elements are printed to the user: |
|---|
| 178 | (default: 'poly') |
|---|
| 179 | 'log': repr is element.log_repr() |
|---|
| 180 | 'int': repr is element.int_repr() |
|---|
| 181 | 'poly': repr is element.poly_repr() |
|---|
| 182 | cache -- if True a cache of all elements of this field is |
|---|
| 183 | created. Thus, arithmetic does not create new |
|---|
| 184 | elements which speeds calculations up. Also, if |
|---|
| 185 | many elements are needed during a calculation |
|---|
| 186 | this cache reduces the memory requirement as at |
|---|
| 187 | most self.order() elements are created. (default: False) |
|---|
| 188 | |
|---|
| 189 | OUTPUT: |
|---|
| 190 | Givaro finite field with characteristic p and cardinality p^n. |
|---|
| 191 | |
|---|
| 192 | EXAMPLES: |
|---|
| 193 | |
|---|
| 194 | By default conway polynomials are used: |
|---|
| 195 | |
|---|
| 196 | sage: k.<a> = GF(2**8) |
|---|
| 197 | sage: -a ^ k.degree() |
|---|
| 198 | a^4 + a^3 + a^2 + 1 |
|---|
| 199 | sage: f = k.modulus(); f |
|---|
| 200 | x^8 + x^4 + x^3 + x^2 + 1 |
|---|
| 201 | |
|---|
| 202 | |
|---|
| 203 | You may enforce a modulus: |
|---|
| 204 | |
|---|
| 205 | sage: P.<x> = PolynomialRing(GF(2)) |
|---|
| 206 | sage: f = x^8 + x^4 + x^3 + x + 1 # Rijndael Polynomial |
|---|
| 207 | sage: k.<a> = GF(2^8, modulus=f) |
|---|
| 208 | sage: k.modulus() |
|---|
| 209 | x^8 + x^4 + x^3 + x + 1 |
|---|
| 210 | sage: a^(2^8) |
|---|
| 211 | a |
|---|
| 212 | |
|---|
| 213 | You may enforce a random modulus: |
|---|
| 214 | |
|---|
| 215 | sage: k = GF(3**5, 'a', modulus='random') |
|---|
| 216 | sage: k.modulus() # random polynomial |
|---|
| 217 | x^5 + 2*x^4 + 2*x^3 + x^2 + 2 |
|---|
| 218 | |
|---|
| 219 | Three different representations are possible: |
|---|
| 220 | |
|---|
| 221 | sage: sage.rings.finite_field_givaro.FiniteField_givaro(9,repr='poly').gen() |
|---|
| 222 | a |
|---|
| 223 | sage: sage.rings.finite_field_givaro.FiniteField_givaro(9,repr='int').gen() |
|---|
| 224 | 3 |
|---|
| 225 | sage: sage.rings.finite_field_givaro.FiniteField_givaro(9,repr='log').gen() |
|---|
| 226 | 5 |
|---|
| 227 | """ |
|---|
| 228 | |
|---|
| 229 | # we are calling late_import here because this constructor is |
|---|
| 230 | # called at least once before any arithmetic is perfored. |
|---|
| 231 | late_import() |
|---|
| 232 | |
|---|
| 233 | cdef intvec cPoly |
|---|
| 234 | |
|---|
| 235 | if repr=='poly': |
|---|
| 236 | self.repr = 0 |
|---|
| 237 | elif repr=='log': |
|---|
| 238 | self.repr = 1 |
|---|
| 239 | elif repr=='int': |
|---|
| 240 | self.repr = 2 |
|---|
| 241 | else: |
|---|
| 242 | raise ValueError, "Unknown representation %s"%repr |
|---|
| 243 | |
|---|
| 244 | if q >= 1<<16: |
|---|
| 245 | raise ArithmeticError, "q must be < 2^16" |
|---|
| 246 | |
|---|
| 247 | q = Integer(q) |
|---|
| 248 | if q < 2: |
|---|
| 249 | raise ArithmeticError, "q must be a prime power" |
|---|
| 250 | F = q.factor() |
|---|
| 251 | if len(F) > 1: |
|---|
| 252 | raise ArithmeticError, "q must be a prime power" |
|---|
| 253 | p = F[0][0] |
|---|
| 254 | k = F[0][1] |
|---|
| 255 | |
|---|
| 256 | ParentWithGens.__init__(self, finite_field.FiniteField(p), name, normalize=False) |
|---|
| 257 | |
|---|
| 258 | self._is_conway = False |
|---|
| 259 | if modulus is None or modulus=="random": |
|---|
| 260 | if k>1 and ConwayPolynomials().has_polynomial(p, k) and modulus!="random": |
|---|
| 261 | modulus = conway_polynomial(p, k) |
|---|
| 262 | self._is_conway = True |
|---|
| 263 | else: |
|---|
| 264 | _sig_on |
|---|
| 265 | self.objectptr = gfq_factorypk(p,k) |
|---|
| 266 | self._zero_element = make_FiniteField_givaroElement(self,self.objectptr.zero) |
|---|
| 267 | self._one_element = make_FiniteField_givaroElement(self,self.objectptr.one) |
|---|
| 268 | _sig_off |
|---|
| 269 | if cache: |
|---|
| 270 | self._array = self.gen_array() |
|---|
| 271 | return |
|---|
| 272 | |
|---|
| 273 | if is_Polynomial(modulus): |
|---|
| 274 | modulus = modulus.list() |
|---|
| 275 | |
|---|
| 276 | if PY_TYPE_CHECK(modulus, list) or PY_TYPE_CHECK(modulus, tuple): |
|---|
| 277 | |
|---|
| 278 | for i from 0 <= i < len(modulus): |
|---|
| 279 | cPoly.push_back(int( modulus[i] % p )) |
|---|
| 280 | |
|---|
| 281 | _sig_on |
|---|
| 282 | self.objectptr = gfq_factorypkp(p, k,cPoly) |
|---|
| 283 | _sig_off |
|---|
| 284 | self._zero_element = make_FiniteField_givaroElement(self,self.objectptr.zero) |
|---|
| 285 | self._one_element = make_FiniteField_givaroElement(self,self.objectptr.one) |
|---|
| 286 | |
|---|
| 287 | if cache: |
|---|
| 288 | self._array = self.gen_array() |
|---|
| 289 | return |
|---|
| 290 | |
|---|
| 291 | raise TypeError, "Cannot understand modulus" |
|---|
| 292 | |
|---|
| 293 | cdef gen_array(FiniteField_givaro self): |
|---|
| 294 | """ |
|---|
| 295 | Generates an array/list/tuple containing all elements of self indexed by their |
|---|
| 296 | power with respect to the internal generator. |
|---|
| 297 | """ |
|---|
| 298 | cdef int i |
|---|
| 299 | |
|---|
| 300 | array = list() |
|---|
| 301 | for i from 0 <= i < self.order_c(): |
|---|
| 302 | array.append( make_FiniteField_givaroElement(self,i) ) |
|---|
| 303 | return tuple(array) |
|---|
| 304 | |
|---|
| 305 | def __dealloc__(FiniteField_givaro self): |
|---|
| 306 | """ |
|---|
| 307 | Free the memory occupied by this Givaro finite field. |
|---|
| 308 | """ |
|---|
| 309 | delete(self.objectptr) |
|---|
| 310 | |
|---|
| 311 | def __repr__(FiniteField_givaro self): |
|---|
| 312 | if self.degree()>1: |
|---|
| 313 | return "Finite Field in %s of size %d^%d"%(self.variable_name(),self.characteristic(),self.degree()) |
|---|
| 314 | else: |
|---|
| 315 | return "Finite Field of size %d"%(self.characteristic()) |
|---|
| 316 | |
|---|
| 317 | def characteristic(FiniteField_givaro self): |
|---|
| 318 | """ |
|---|
| 319 | Return the characteristic of this field. |
|---|
| 320 | |
|---|
| 321 | EXAMPLES: |
|---|
| 322 | sage: p = GF(19^5,'a').characteristic(); p |
|---|
| 323 | 19 |
|---|
| 324 | sage: type(p) |
|---|
| 325 | <type 'sage.rings.integer.Integer'> |
|---|
| 326 | """ |
|---|
| 327 | return Integer(self.objectptr.characteristic()) |
|---|
| 328 | |
|---|
| 329 | def order(FiniteField_givaro self): |
|---|
| 330 | """ |
|---|
| 331 | Return the cardinality of this field. |
|---|
| 332 | |
|---|
| 333 | OUTPUT: |
|---|
| 334 | Integer -- the number of elements in self. |
|---|
| 335 | |
|---|
| 336 | EXAMPLES: |
|---|
| 337 | sage: n = GF(19^5,'a').order(); n |
|---|
| 338 | 2476099 |
|---|
| 339 | sage: type(n) |
|---|
| 340 | <type 'sage.rings.integer.Integer'> |
|---|
| 341 | """ |
|---|
| 342 | return Integer(self.order_c()) |
|---|
| 343 | |
|---|
| 344 | cdef order_c(FiniteField_givaro self): |
|---|
| 345 | return self.objectptr.cardinality() |
|---|
| 346 | |
|---|
| 347 | |
|---|
| 348 | def cardinality(FiniteField_givaro self): |
|---|
| 349 | """ |
|---|
| 350 | Return the cardinality of this field. |
|---|
| 351 | |
|---|
| 352 | OUTPUT: |
|---|
| 353 | Integer -- the cardinality of self. |
|---|
| 354 | |
|---|
| 355 | NOTE: this is the same as self.order() |
|---|
| 356 | |
|---|
| 357 | EXAMPLES: |
|---|
| 358 | sage: GF(3^4,'a').cardinality() |
|---|
| 359 | 81 |
|---|
| 360 | """ |
|---|
| 361 | return int(self.objectptr.cardinality()) |
|---|
| 362 | |
|---|
| 363 | def __len__(self): |
|---|
| 364 | """ |
|---|
| 365 | len(k) is returns the cardlinality of k, i.e., the number of elements in k. |
|---|
| 366 | |
|---|
| 367 | EXAMPLE: |
|---|
| 368 | sage: k = GF(23**3, 'a') |
|---|
| 369 | sage: len(k) |
|---|
| 370 | 12167 |
|---|
| 371 | sage: k = GF(2) |
|---|
| 372 | sage: len(k) |
|---|
| 373 | 2 |
|---|
| 374 | """ |
|---|
| 375 | return self.order_c() |
|---|
| 376 | |
|---|
| 377 | def degree(FiniteField_givaro self): |
|---|
| 378 | r""" |
|---|
| 379 | If \code{self.cardinality() == p^n} this method returns $n$. |
|---|
| 380 | |
|---|
| 381 | OUTPUT: |
|---|
| 382 | Integer -- the degree |
|---|
| 383 | |
|---|
| 384 | EXAMPLES: |
|---|
| 385 | sage: GF(3^4,'a').degree() |
|---|
| 386 | 4 |
|---|
| 387 | """ |
|---|
| 388 | return Integer(self.objectptr.exponent()) |
|---|
| 389 | |
|---|
| 390 | def is_atomic_repr(FiniteField_givaro self): |
|---|
| 391 | """ |
|---|
| 392 | Return whether elements of self are printed using an atomic |
|---|
| 393 | representation. |
|---|
| 394 | |
|---|
| 395 | EXAMPLES: |
|---|
| 396 | sage: GF(3^4,'a').is_atomic_repr() |
|---|
| 397 | False |
|---|
| 398 | """ |
|---|
| 399 | if self.repr==0: #modulus |
|---|
| 400 | return False |
|---|
| 401 | else: |
|---|
| 402 | return True |
|---|
| 403 | |
|---|
| 404 | def is_prime_field(FiniteField_givaro self): |
|---|
| 405 | """ |
|---|
| 406 | Return True if self is a prime field, i.e., has degree 1. |
|---|
| 407 | |
|---|
| 408 | EXAMPLES: |
|---|
| 409 | sage: GF(3^7, 'a').is_prime_field() |
|---|
| 410 | False |
|---|
| 411 | sage: GF(3, 'a').is_prime_field() |
|---|
| 412 | True |
|---|
| 413 | """ |
|---|
| 414 | return self.degree()==1 |
|---|
| 415 | |
|---|
| 416 | def is_prime(FiniteField_givaro self): |
|---|
| 417 | """ |
|---|
| 418 | Return True if self has prime cardinality. |
|---|
| 419 | |
|---|
| 420 | EXAMPLES: |
|---|
| 421 | sage: GF(3, 'a').is_prime() |
|---|
| 422 | True |
|---|
| 423 | """ |
|---|
| 424 | return self.degree()==1 |
|---|
| 425 | |
|---|
| 426 | def random_element(FiniteField_givaro self): |
|---|
| 427 | """ |
|---|
| 428 | Return a random element of self. |
|---|
| 429 | |
|---|
| 430 | EXAMPLES: |
|---|
| 431 | sage: k = GF(23**3, 'a') |
|---|
| 432 | sage: e = k.random_element() |
|---|
| 433 | sage: type(e) |
|---|
| 434 | <type 'sage.rings.finite_field_givaro.FiniteField_givaroElement'> |
|---|
| 435 | """ |
|---|
| 436 | cdef int res |
|---|
| 437 | cdef GivRandom generator |
|---|
| 438 | res = self.objectptr.random(generator,res) |
|---|
| 439 | return make_FiniteField_givaroElement(self,res) |
|---|
| 440 | |
|---|
| 441 | def __call__(FiniteField_givaro self, e): |
|---|
| 442 | """ |
|---|
| 443 | Coerces several data types to self. |
|---|
| 444 | |
|---|
| 445 | INPUT: |
|---|
| 446 | e -- data to coerce |
|---|
| 447 | |
|---|
| 448 | EXAMPLES: |
|---|
| 449 | |
|---|
| 450 | FiniteField_givaroElement are accepted where the parent |
|---|
| 451 | is either self, equals self or is the prime subfield |
|---|
| 452 | |
|---|
| 453 | sage: k = GF(2**8, 'a') |
|---|
| 454 | sage: k.gen() == k(k.gen()) |
|---|
| 455 | True |
|---|
| 456 | |
|---|
| 457 | |
|---|
| 458 | Floats, ints, longs, Integer are interpreted modulo characteristic |
|---|
| 459 | |
|---|
| 460 | sage: k(2) |
|---|
| 461 | 0 |
|---|
| 462 | |
|---|
| 463 | Floats coerce in: |
|---|
| 464 | sage: k(float(2.0)) |
|---|
| 465 | 0 |
|---|
| 466 | |
|---|
| 467 | Rational are interpreted as |
|---|
| 468 | self(numerator)/self(denominator). |
|---|
| 469 | Both may not be >= self.characteristic(). |
|---|
| 470 | |
|---|
| 471 | sage: k = GF(3**8, 'a') |
|---|
| 472 | sage: k(1/2) == k(1)/k(2) |
|---|
| 473 | True |
|---|
| 474 | |
|---|
| 475 | Free modulo elements over self.prime_subfield() are interpreted 'little endian' |
|---|
| 476 | |
|---|
| 477 | sage: k = GF(2**8, 'a') |
|---|
| 478 | sage: e = k.vector_space().gen(1); e |
|---|
| 479 | (0, 1, 0, 0, 0, 0, 0, 0) |
|---|
| 480 | sage: k(e) |
|---|
| 481 | a |
|---|
| 482 | |
|---|
| 483 | Strings are evaluated as polynomial representation of elements in self |
|---|
| 484 | |
|---|
| 485 | sage: k('a^2+1') |
|---|
| 486 | a^2 + 1 |
|---|
| 487 | |
|---|
| 488 | PARI elements are interpreted as finite field elements; this PARI flexibility |
|---|
| 489 | is (absurdly!) liberal: |
|---|
| 490 | |
|---|
| 491 | sage: k(pari('Mod(1,2)')) |
|---|
| 492 | 1 |
|---|
| 493 | sage: k(pari('Mod(2,3)')) |
|---|
| 494 | 0 |
|---|
| 495 | sage: k(pari('Mod(1,3)*a^20')) |
|---|
| 496 | a^7 + a^5 + a^4 + a^2 |
|---|
| 497 | |
|---|
| 498 | GAP elements need to be finite field elements: |
|---|
| 499 | |
|---|
| 500 | sage: from sage.rings.finite_field_givaro import FiniteField_givaro |
|---|
| 501 | sage: x = gap('Z(13)') |
|---|
| 502 | sage: F = FiniteField_givaro(13) |
|---|
| 503 | sage: F(x) |
|---|
| 504 | 2 |
|---|
| 505 | sage: F(gap('0*Z(13)')) |
|---|
| 506 | 0 |
|---|
| 507 | sage: F = FiniteField_givaro(13^2) |
|---|
| 508 | sage: x = gap('Z(13)') |
|---|
| 509 | sage: F(x) |
|---|
| 510 | 2 |
|---|
| 511 | sage: x = gap('Z(13^2)^3') |
|---|
| 512 | sage: F(x) |
|---|
| 513 | 12*a + 11 |
|---|
| 514 | sage: F.multiplicative_generator()^3 |
|---|
| 515 | 12*a + 11 |
|---|
| 516 | |
|---|
| 517 | sage: k.<a> = GF(29^3) |
|---|
| 518 | sage: k(48771/1225) |
|---|
| 519 | 28 |
|---|
| 520 | |
|---|
| 521 | """ |
|---|
| 522 | |
|---|
| 523 | cdef int res |
|---|
| 524 | cdef int g |
|---|
| 525 | cdef int x |
|---|
| 526 | cdef int e_int |
|---|
| 527 | |
|---|
| 528 | |
|---|
| 529 | ######## |
|---|
| 530 | |
|---|
| 531 | if PY_TYPE_CHECK(e, FiniteField_givaroElement): |
|---|
| 532 | if e.parent() is self: |
|---|
| 533 | return e |
|---|
| 534 | if e.parent() == self: |
|---|
| 535 | return make_FiniteField_givaroElement(self,(<FiniteField_givaroElement>e).element) |
|---|
| 536 | if e.parent() is self.prime_subfield_C() or e.parent() == self.prime_subfield_C(): |
|---|
| 537 | res = self.int_to_log(int(e)) |
|---|
| 538 | |
|---|
| 539 | elif PY_TYPE_CHECK(e, int) or \ |
|---|
| 540 | PY_TYPE_CHECK(e, Integer) or \ |
|---|
| 541 | PY_TYPE_CHECK(e, long) or is_IntegerMod(e): |
|---|
| 542 | try: |
|---|
| 543 | e_int = e |
|---|
| 544 | if e != e_int: # overflow in Pyrex is often not detected correctly... but this is bullet proof. |
|---|
| 545 | # sometimes it is detected correctly, so we do have to use exceptions though. |
|---|
| 546 | # todo -- be more eloquent here!! |
|---|
| 547 | raise OverflowError |
|---|
| 548 | res = self.objectptr.initi(res,e_int) |
|---|
| 549 | except OverflowError: |
|---|
| 550 | res = self.objectptr.initi(res,int(e)%int(self.objectptr.characteristic())) |
|---|
| 551 | |
|---|
| 552 | elif PY_TYPE_CHECK(e, float): |
|---|
| 553 | res = self.objectptr.initd(res,e) |
|---|
| 554 | |
|---|
| 555 | elif PY_TYPE_CHECK(e, str): |
|---|
| 556 | return self(eval(e.replace("^","**"),{str(self.variable_name()):self.gen()})) |
|---|
| 557 | |
|---|
| 558 | elif PY_TYPE_CHECK(e, FreeModuleElement): |
|---|
| 559 | if self.vector_space() != e.parent(): |
|---|
| 560 | raise TypeError, "e.parent must match self.vector_space" |
|---|
| 561 | ret = self.zero() |
|---|
| 562 | for i in range(len(e)): |
|---|
| 563 | ret = ret + self(int(e[i]))*self.gen()**i |
|---|
| 564 | return ret |
|---|
| 565 | |
|---|
| 566 | elif PY_TYPE_CHECK(e, MPolynomial) or PY_TYPE_CHECK(e, Polynomial): |
|---|
| 567 | if e.is_constant(): |
|---|
| 568 | return self(e.constant_coefficient()) |
|---|
| 569 | else: |
|---|
| 570 | raise TypeError, "no coercion defined" |
|---|
| 571 | |
|---|
| 572 | elif PY_TYPE_CHECK(e, Rational): |
|---|
| 573 | num = e.numer() |
|---|
| 574 | den = e.denom() |
|---|
| 575 | return self(num)/self(den) |
|---|
| 576 | |
|---|
| 577 | elif PY_TYPE_CHECK(e, gen): |
|---|
| 578 | pass # handle this in next if clause |
|---|
| 579 | |
|---|
| 580 | elif PY_TYPE_CHECK(e,FiniteField_ext_pariElement): |
|---|
| 581 | # reduce FiniteFieldElements to pari |
|---|
| 582 | e = e._pari_() |
|---|
| 583 | |
|---|
| 584 | elif sage.interfaces.gap.is_GapElement(e): |
|---|
| 585 | return gap_to_givaro_c(e, self) |
|---|
| 586 | |
|---|
| 587 | else: |
|---|
| 588 | raise TypeError, "unable to coerce" |
|---|
| 589 | |
|---|
| 590 | if PY_TYPE_CHECK(e, gen): |
|---|
| 591 | e = e.lift().lift() |
|---|
| 592 | try: |
|---|
| 593 | res = self.int_to_log(e[0]) |
|---|
| 594 | except TypeError: |
|---|
| 595 | res = self.int_to_log(e) |
|---|
| 596 | |
|---|
| 597 | g = self.objectptr.sage_generator() |
|---|
| 598 | x = self.objectptr.one |
|---|
| 599 | |
|---|
| 600 | for i from 0 < i <= e.poldegree(): |
|---|
| 601 | x = self.objectptr.mul(x,x,g) |
|---|
| 602 | res = self.objectptr.axpyin( res, self.int_to_log(e[i]) , x) |
|---|
| 603 | |
|---|
| 604 | return make_FiniteField_givaroElement(self,res) |
|---|
| 605 | |
|---|
| 606 | cdef _coerce_c_impl(self, x): |
|---|
| 607 | """ |
|---|
| 608 | Coercion accepts elements of self.parent(), ints, and prime subfield elements. |
|---|
| 609 | """ |
|---|
| 610 | cdef int r, cx |
|---|
| 611 | |
|---|
| 612 | if PY_TYPE_CHECK(x, int) \ |
|---|
| 613 | or PY_TYPE_CHECK(x, long) or PY_TYPE_CHECK(x, Integer): |
|---|
| 614 | cx = x % self.characteristic() |
|---|
| 615 | r = (<FiniteField_givaro>self).objectptr.initi(r, cx%self.objectptr.characteristic()) |
|---|
| 616 | return make_FiniteField_givaroElement(<FiniteField_givaro>self,r) |
|---|
| 617 | |
|---|
| 618 | if PY_TYPE_CHECK(x, FiniteFieldElement) or \ |
|---|
| 619 | PY_TYPE_CHECK(x, FiniteField_givaroElement) or is_IntegerMod(x): |
|---|
| 620 | K = x.parent() |
|---|
| 621 | if K is <object>self: |
|---|
| 622 | return x |
|---|
| 623 | if PY_TYPE_CHECK(K, IntegerModRing_generic) \ |
|---|
| 624 | and K.characteristic() % self.characteristic() == 0: |
|---|
| 625 | return self(int(x)) |
|---|
| 626 | if K.characteristic() == self.characteristic(): |
|---|
| 627 | if K.degree() == 1: |
|---|
| 628 | return self(int(x)) |
|---|
| 629 | elif self.degree() % K.degree() == 0: |
|---|
| 630 | # This is where we *would* do coercion from one nontrivial finite field to another... |
|---|
| 631 | raise TypeError, 'no canonical coercion defined' |
|---|
| 632 | raise TypeError, 'no canonical coercion defined' |
|---|
| 633 | |
|---|
| 634 | |
|---|
| 635 | def one(FiniteField_givaro self): |
|---|
| 636 | """ |
|---|
| 637 | Return 1 element in self, which satisfies 1*p=p for every |
|---|
| 638 | element of self != 0. |
|---|
| 639 | |
|---|
| 640 | EXAMPLES: |
|---|
| 641 | sage: k = GF(3^4, 'b'); k |
|---|
| 642 | Finite Field in b of size 3^4 |
|---|
| 643 | sage: o = k.one(); o |
|---|
| 644 | 1 |
|---|
| 645 | sage: o == 1 |
|---|
| 646 | True |
|---|
| 647 | sage: o is k.one() |
|---|
| 648 | True |
|---|
| 649 | """ |
|---|
| 650 | return self._one_element |
|---|
| 651 | |
|---|
| 652 | def zero(FiniteField_givaro self): |
|---|
| 653 | """ |
|---|
| 654 | Return 0 element in self, which satisfies 0+p=p for every |
|---|
| 655 | element of self. |
|---|
| 656 | |
|---|
| 657 | EXAMPLES: |
|---|
| 658 | sage: k = GF(3^4, 'b'); k |
|---|
| 659 | Finite Field in b of size 3^4 |
|---|
| 660 | sage: o = k.zero(); o |
|---|
| 661 | 0 |
|---|
| 662 | sage: o == 0 |
|---|
| 663 | True |
|---|
| 664 | sage: o is k.zero() |
|---|
| 665 | True |
|---|
| 666 | """ |
|---|
| 667 | return self._zero_element |
|---|
| 668 | |
|---|
| 669 | |
|---|
| 670 | def gen(FiniteField_givaro self, ignored=None): |
|---|
| 671 | r""" |
|---|
| 672 | Return a generator of self. All elements x of self are |
|---|
| 673 | expressed as $\log_{self.gen()}(p)$ internally. If self is |
|---|
| 674 | a prime field this method returns 1. |
|---|
| 675 | |
|---|
| 676 | EXAMPLES: |
|---|
| 677 | sage: k = GF(3^4, 'b'); k.gen() |
|---|
| 678 | b |
|---|
| 679 | """ |
|---|
| 680 | cdef int r |
|---|
| 681 | from sage.rings.arith import primitive_root |
|---|
| 682 | |
|---|
| 683 | if self.degree() == 1: |
|---|
| 684 | return self(primitive_root(self.order_c())) |
|---|
| 685 | else: |
|---|
| 686 | return make_FiniteField_givaroElement(self,self.objectptr.sage_generator()) |
|---|
| 687 | |
|---|
| 688 | cdef prime_subfield_C(FiniteField_givaro self): |
|---|
| 689 | if self._prime_subfield is None: |
|---|
| 690 | self._prime_subfield = finite_field.FiniteField(self.characteristic()) |
|---|
| 691 | return self._prime_subfield |
|---|
| 692 | |
|---|
| 693 | def prime_subfield(FiniteField_givaro self): |
|---|
| 694 | r""" |
|---|
| 695 | Return the prime subfield $\FF_p$ of self if self is $\FF_{p^n}$. |
|---|
| 696 | |
|---|
| 697 | EXAMPLES: |
|---|
| 698 | sage: GF(3^4, 'b').prime_subfield() |
|---|
| 699 | Finite Field of size 3 |
|---|
| 700 | |
|---|
| 701 | sage: S.<b> = GF(5^2); S |
|---|
| 702 | Finite Field in b of size 5^2 |
|---|
| 703 | sage: S.prime_subfield() |
|---|
| 704 | Finite Field of size 5 |
|---|
| 705 | sage: type(S.prime_subfield()) |
|---|
| 706 | <class 'sage.rings.finite_field.FiniteField_prime_modn'> |
|---|
| 707 | """ |
|---|
| 708 | return self.prime_subfield_C() |
|---|
| 709 | |
|---|
| 710 | |
|---|
| 711 | def log_to_int(FiniteField_givaro self, int n): |
|---|
| 712 | r""" |
|---|
| 713 | Given an integer $n$ this method returns $i$ where $i$ |
|---|
| 714 | satisfies \code{self.gen()^n == i}, if the result is |
|---|
| 715 | interpreted as an integer. |
|---|
| 716 | |
|---|
| 717 | INPUT: |
|---|
| 718 | n -- log representation of a finite field element |
|---|
| 719 | |
|---|
| 720 | OUTPUT: |
|---|
| 721 | integer representation of a finite field element. |
|---|
| 722 | |
|---|
| 723 | EXAMPLE: |
|---|
| 724 | sage: k = GF(2**8, 'a') |
|---|
| 725 | sage: k.log_to_int(4) |
|---|
| 726 | 16 |
|---|
| 727 | sage: k.log_to_int(20) |
|---|
| 728 | 180 |
|---|
| 729 | """ |
|---|
| 730 | cdef int ret |
|---|
| 731 | |
|---|
| 732 | if n<0: |
|---|
| 733 | raise ArithmeticError, "Cannot serve negative exponent %d"%n |
|---|
| 734 | elif n>=self.order_c(): |
|---|
| 735 | raise IndexError, "n=%d must be < self.order()"%n |
|---|
| 736 | _sig_on |
|---|
| 737 | ret = int(self.objectptr.convert(ret, n)) |
|---|
| 738 | _sig_off |
|---|
| 739 | return ret |
|---|
| 740 | |
|---|
| 741 | def int_to_log(FiniteField_givaro self, int n): |
|---|
| 742 | r""" |
|---|
| 743 | Given an integer $n$ this method returns $i$ where $i$ satisfies |
|---|
| 744 | \code{self.gen()^i==(n\%self.characteristic())}. |
|---|
| 745 | |
|---|
| 746 | INPUT: |
|---|
| 747 | n -- integer representation of an finite field element |
|---|
| 748 | |
|---|
| 749 | OUTPUT: |
|---|
| 750 | log representation of n |
|---|
| 751 | |
|---|
| 752 | EXAMPLE: |
|---|
| 753 | sage: k = GF(7**3, 'a') |
|---|
| 754 | sage: k.int_to_log(4) |
|---|
| 755 | 228 |
|---|
| 756 | sage: k.int_to_log(3) |
|---|
| 757 | 57 |
|---|
| 758 | sage: k.gen()^57 |
|---|
| 759 | 3 |
|---|
| 760 | """ |
|---|
| 761 | cdef int r |
|---|
| 762 | _sig_on |
|---|
| 763 | ret = int(self.objectptr.initi(r,n)) |
|---|
| 764 | _sig_off |
|---|
| 765 | return ret |
|---|
| 766 | |
|---|
| 767 | def fetch_int(FiniteField_givaro self, int n): |
|---|
| 768 | r""" |
|---|
| 769 | Given an integer $n$ return a finite field element in self |
|---|
| 770 | which equals $n$ under the condition that self.gen() is set to |
|---|
| 771 | self.characteristic(). |
|---|
| 772 | |
|---|
| 773 | EXAMPLE: |
|---|
| 774 | sage: k.<a> = GF(2^8) |
|---|
| 775 | sage: k.fetch_int(8) |
|---|
| 776 | a^3 |
|---|
| 777 | sage: e = k.fetch_int(151); e |
|---|
| 778 | a^7 + a^4 + a^2 + a + 1 |
|---|
| 779 | sage: 2^7 + 2^4 + 2^2 + 2 + 1 |
|---|
| 780 | 151 |
|---|
| 781 | """ |
|---|
| 782 | cdef GivaroGfq *k = self.objectptr |
|---|
| 783 | cdef int ret = k.zero |
|---|
| 784 | cdef int a = k.sage_generator() |
|---|
| 785 | cdef int at = k.one |
|---|
| 786 | cdef unsigned int ch = k.characteristic() |
|---|
| 787 | cdef int _n, t, i |
|---|
| 788 | |
|---|
| 789 | if n<0 or n>k.cardinality(): |
|---|
| 790 | raise TypeError, "n must be between 0 and self.order()" |
|---|
| 791 | |
|---|
| 792 | _n = n |
|---|
| 793 | |
|---|
| 794 | for i from 0 <= i < k.exponent(): |
|---|
| 795 | t = k.initi(t, _n%ch) |
|---|
| 796 | ret = k.axpy(ret, t, at, ret) |
|---|
| 797 | at = k.mul(at,at,a) |
|---|
| 798 | _n = _n/ch |
|---|
| 799 | return make_FiniteField_givaroElement(self, ret) |
|---|
| 800 | |
|---|
| 801 | def polynomial(self): |
|---|
| 802 | """ |
|---|
| 803 | Return the defining polynomial of this field as an element of |
|---|
| 804 | self.polynomial_ring(). |
|---|
| 805 | |
|---|
| 806 | This is the same as the characteristic polynomial of the |
|---|
| 807 | generator of self. |
|---|
| 808 | |
|---|
| 809 | EXAMPLES: |
|---|
| 810 | sage: k = GF(3^4, 'a') |
|---|
| 811 | sage: k.polynomial() |
|---|
| 812 | a^4 + 2*a^3 + 2 |
|---|
| 813 | """ |
|---|
| 814 | if self._polynomial is None: |
|---|
| 815 | quo = int(-(self.gen()**(self.degree()))) |
|---|
| 816 | b = int(self.characteristic()) |
|---|
| 817 | |
|---|
| 818 | ret = [] |
|---|
| 819 | for i in range(self.degree()): |
|---|
| 820 | ret.append(quo%b) |
|---|
| 821 | quo = quo/b |
|---|
| 822 | ret = ret + [1] |
|---|
| 823 | R = self.polynomial_ring_c(None) |
|---|
| 824 | self._polynomial = R(ret) |
|---|
| 825 | return self._polynomial |
|---|
| 826 | |
|---|
| 827 | def modulus(self): |
|---|
| 828 | r""" |
|---|
| 829 | Return the minimal polynomial of the generator of self in |
|---|
| 830 | \code{self.polynomial_ring('x')}. |
|---|
| 831 | |
|---|
| 832 | EXAMPLES: |
|---|
| 833 | sage: k = GF(3^5, 'a') |
|---|
| 834 | sage: k.modulus() |
|---|
| 835 | x^5 + 2*x + 1 |
|---|
| 836 | |
|---|
| 837 | sage: k.polynomial() |
|---|
| 838 | a^5 + 2*a + 1 |
|---|
| 839 | """ |
|---|
| 840 | return self.polynomial_ring_c("x")(self.polynomial().list()) |
|---|
| 841 | |
|---|
| 842 | def _pari_modulus(self): |
|---|
| 843 | """ |
|---|
| 844 | EXAMPLES: |
|---|
| 845 | sage: GF(3^4,'a')._pari_modulus() |
|---|
| 846 | Mod(1, 3)*a^4 + Mod(2, 3)*a^3 + Mod(2, 3) |
|---|
| 847 | """ |
|---|
| 848 | f = pari(str(self.modulus())) |
|---|
| 849 | return f.subst('x', 'a') * pari("Mod(1,%s)"%self.characteristic()) |
|---|
| 850 | |
|---|
| 851 | cdef polynomial_ring_c(self, variable_name): |
|---|
| 852 | if self._polynomial_ring is None or variable_name is not None: |
|---|
| 853 | from sage.rings.polynomial.polynomial_ring import PolynomialRing |
|---|
| 854 | if variable_name is None: |
|---|
| 855 | # todo: is this cache necessary? |
|---|
| 856 | self._polynomial_ring = PolynomialRing(self.prime_subfield_C(),self.variable_name()) |
|---|
| 857 | return self._polynomial_ring |
|---|
| 858 | else: |
|---|
| 859 | return PolynomialRing(self.prime_subfield_C(), variable_name) |
|---|
| 860 | else: |
|---|
| 861 | return self._polynomial_ring |
|---|
| 862 | |
|---|
| 863 | def polynomial_ring(self): |
|---|
| 864 | """ |
|---|
| 865 | Return the polynomial ring over the prime subfield in the |
|---|
| 866 | same variable as this finite field. |
|---|
| 867 | |
|---|
| 868 | EXAMPLES: |
|---|
| 869 | sage: GF(3^4,'z').polynomial_ring() |
|---|
| 870 | Univariate Polynomial Ring in z over Finite Field of size 3 |
|---|
| 871 | """ |
|---|
| 872 | return self.polynomial_ring_c(None) |
|---|
| 873 | |
|---|
| 874 | def _finite_field_ext_pari_(self): # todo -- cache |
|---|
| 875 | """ |
|---|
| 876 | Return a FiniteField_ext_pari isomorphic to self with the same |
|---|
| 877 | defining polynomial. |
|---|
| 878 | |
|---|
| 879 | EXAMPLES: |
|---|
| 880 | sage: GF(3^4,'z')._finite_field_ext_pari_() |
|---|
| 881 | Finite Field in z of size 3^4 |
|---|
| 882 | """ |
|---|
| 883 | f = self.polynomial() |
|---|
| 884 | return finite_field.FiniteField_ext_pari(self.order_c(), |
|---|
| 885 | self.variable_name(), f) |
|---|
| 886 | |
|---|
| 887 | def _finite_field_ext_pari_modulus_as_str(self): # todo -- cache |
|---|
| 888 | return self._finite_field_ext_pari_().modulus()._pari_init_() |
|---|
| 889 | |
|---|
| 890 | def vector_space(FiniteField_givaroElement self): |
|---|
| 891 | """ |
|---|
| 892 | Returns self interpreted as a VectorSpace over |
|---|
| 893 | self.prime_subfield() |
|---|
| 894 | |
|---|
| 895 | EXAMPLE: |
|---|
| 896 | sage: k = GF(3**5, 'a') |
|---|
| 897 | sage: k.vector_space() |
|---|
| 898 | Vector space of dimension 5 over Finite Field of size 3 |
|---|
| 899 | |
|---|
| 900 | """ |
|---|
| 901 | import sage.modules.all |
|---|
| 902 | V = sage.modules.all.VectorSpace(self.prime_subfield(),self.degree()) |
|---|
| 903 | return V |
|---|
| 904 | |
|---|
| 905 | def __iter__(FiniteField_givaro self): |
|---|
| 906 | """ |
|---|
| 907 | Finite fields may be iterated over: |
|---|
| 908 | |
|---|
| 909 | EXAMPLE: |
|---|
| 910 | sage: list(GF(2**2, 'a')) |
|---|
| 911 | [0, a, a + 1, 1] |
|---|
| 912 | """ |
|---|
| 913 | return FiniteField_givaro_iterator(self) |
|---|
| 914 | |
|---|
| 915 | def __richcmp__(left, right, int op): |
|---|
| 916 | return (<Parent>left)._richcmp(right, op) |
|---|
| 917 | |
|---|
| 918 | cdef int _cmp_c_impl(left, Parent right) except -2: |
|---|
| 919 | """ |
|---|
| 920 | Finite Fields are considered to be equal if |
|---|
| 921 | * their implementation is the same (Givaro) |
|---|
| 922 | * their characteristics match |
|---|
| 923 | * their degrees match |
|---|
| 924 | * their moduli match if degree > 1 |
|---|
| 925 | |
|---|
| 926 | This will probably change in the future so that different |
|---|
| 927 | implementations are equal. |
|---|
| 928 | """ |
|---|
| 929 | if not isinstance(right, FiniteField_givaro): |
|---|
| 930 | return cmp(type(left), type(right)) |
|---|
| 931 | c = cmp(left.characteristic(), right.characteristic()) |
|---|
| 932 | if c: return c |
|---|
| 933 | c = cmp(left.degree(), right.degree()) |
|---|
| 934 | if c: return c |
|---|
| 935 | # TODO comparing the polynomials themselves would recursively call |
|---|
| 936 | # this cmp... Also, as mentioned above, we will get rid of this. |
|---|
| 937 | if left.degree() > 1: |
|---|
| 938 | c = cmp(str(left.polynomial()), str(right.polynomial())) |
|---|
| 939 | if c: return c |
|---|
| 940 | return 0 |
|---|
| 941 | |
|---|
| 942 | def __hash__(FiniteField_givaro self): |
|---|
| 943 | """ |
|---|
| 944 | The hash of a Givaro finite field is a hash over it's |
|---|
| 945 | characterstic polynomial and the string 'givaro' |
|---|
| 946 | |
|---|
| 947 | EXAMPLES: |
|---|
| 948 | sage: hash(GF(3^4, 'a')) |
|---|
| 949 | 695660592 # 32-bit |
|---|
| 950 | -4281682415996964816 # 64-bit |
|---|
| 951 | """ |
|---|
| 952 | if self._hash is None: |
|---|
| 953 | pass |
|---|
| 954 | if self.degree()>1: |
|---|
| 955 | self._hash = hash((self.characteristic(),self.polynomial(),self.variable_name(),"givaro")) |
|---|
| 956 | else: |
|---|
| 957 | self._hash = hash((self.characteristic(),self.variable_name(),"givaro")) |
|---|
| 958 | return self._hash |
|---|
| 959 | |
|---|
| 960 | def _element_repr(FiniteField_givaro self, FiniteField_givaroElement e): |
|---|
| 961 | """ |
|---|
| 962 | Wrapper for log, int, and poly representations. |
|---|
| 963 | |
|---|
| 964 | EXAMPLES: |
|---|
| 965 | sage: k.<a> = GF(3^4); k |
|---|
| 966 | Finite Field in a of size 3^4 |
|---|
| 967 | sage: k._element_repr(a^20) |
|---|
| 968 | '2*a^3 + 2*a^2 + 2' |
|---|
| 969 | |
|---|
| 970 | sage: k = sage.rings.finite_field_givaro.FiniteField_givaro(3^4,'a', repr='int') |
|---|
| 971 | sage: a = k.gen() |
|---|
| 972 | sage: k._element_repr(a^20) |
|---|
| 973 | '74' |
|---|
| 974 | |
|---|
| 975 | sage: k = sage.rings.finite_field_givaro.FiniteField_givaro(3^4,'a', repr='log') |
|---|
| 976 | sage: a = k.gen() |
|---|
| 977 | sage: k._element_repr(a^20) |
|---|
| 978 | '20' |
|---|
| 979 | """ |
|---|
| 980 | if self.repr==0: |
|---|
| 981 | return self._element_poly_repr(e) |
|---|
| 982 | elif self.repr==1: |
|---|
| 983 | return self._element_log_repr(e) |
|---|
| 984 | else: |
|---|
| 985 | return self._element_int_repr(e) |
|---|
| 986 | |
|---|
| 987 | def _element_log_repr(FiniteField_givaro self, FiniteField_givaroElement e): |
|---|
| 988 | r""" |
|---|
| 989 | Return str(i) where \code{base.gen()^i==self}. |
|---|
| 990 | |
|---|
| 991 | TODO -- this isn't what it does -- see below. |
|---|
| 992 | |
|---|
| 993 | EXAMPLES: |
|---|
| 994 | sage: k.<a> = GF(3^4); k |
|---|
| 995 | Finite Field in a of size 3^4 |
|---|
| 996 | sage: k._element_log_repr(a^20) |
|---|
| 997 | '20' |
|---|
| 998 | sage: k._element_log_repr(a) # TODO -- why 41 ?? why not 1? |
|---|
| 999 | '41' |
|---|
| 1000 | """ |
|---|
| 1001 | return str(int(e.element)) |
|---|
| 1002 | |
|---|
| 1003 | def _element_int_repr(FiniteField_givaro self, FiniteField_givaroElement e): |
|---|
| 1004 | """ |
|---|
| 1005 | Return integer representation of e. |
|---|
| 1006 | |
|---|
| 1007 | Elements of this field are represented as ints in as follows: |
|---|
| 1008 | for $e \in \FF_p[x]$ with $e = a_0 + a_1x + a_2x^2 + \cdots $, $e$ is |
|---|
| 1009 | represented as: $n= a_0 + a_1 p + a_2 p^2 + \cdots$. |
|---|
| 1010 | |
|---|
| 1011 | EXAMPLES: |
|---|
| 1012 | sage: k.<a> = GF(3^4); k |
|---|
| 1013 | Finite Field in a of size 3^4 |
|---|
| 1014 | sage: k._element_int_repr(a^20) |
|---|
| 1015 | '74' |
|---|
| 1016 | """ |
|---|
| 1017 | return str(int(e)) |
|---|
| 1018 | |
|---|
| 1019 | def _element_poly_repr(FiniteField_givaro self, FiniteField_givaroElement e, varname = None): |
|---|
| 1020 | """ |
|---|
| 1021 | Return a polynomial expression in base.gen() of self. |
|---|
| 1022 | |
|---|
| 1023 | EXAMPLES: |
|---|
| 1024 | sage: k.<a> = GF(3^4); k |
|---|
| 1025 | Finite Field in a of size 3^4 |
|---|
| 1026 | sage: k._element_poly_repr(a^20) |
|---|
| 1027 | '2*a^3 + 2*a^2 + 2' |
|---|
| 1028 | """ |
|---|
| 1029 | if varname is None: |
|---|
| 1030 | variable = self.variable_name() |
|---|
| 1031 | else: |
|---|
| 1032 | variable = varname |
|---|
| 1033 | |
|---|
| 1034 | quo = self.log_to_int(e.element) |
|---|
| 1035 | b = int(self.characteristic()) |
|---|
| 1036 | |
|---|
| 1037 | ret = "" |
|---|
| 1038 | for i in range(self.degree()): |
|---|
| 1039 | coeff = quo%b |
|---|
| 1040 | if coeff != 0: |
|---|
| 1041 | if i>0: |
|---|
| 1042 | if coeff==1: |
|---|
| 1043 | coeff="" |
|---|
| 1044 | else: |
|---|
| 1045 | coeff=str(coeff)+"*" |
|---|
| 1046 | if i>1: |
|---|
| 1047 | ret = coeff + variable + "^" + str(i) + " + " + ret |
|---|
| 1048 | else: |
|---|
| 1049 | ret = coeff + variable + " + " + ret |
|---|
| 1050 | else: |
|---|
| 1051 | ret = str(coeff) + " + " + ret |
|---|
| 1052 | quo = quo/b |
|---|
| 1053 | if ret == '': |
|---|
| 1054 | return "0" |
|---|
| 1055 | return ret[:-3] |
|---|
| 1056 | |
|---|
| 1057 | def a_times_b_plus_c(FiniteField_givaro self,FiniteField_givaroElement a, FiniteField_givaroElement b, FiniteField_givaroElement c): |
|---|
| 1058 | """ |
|---|
| 1059 | Return r = a*b + c. This is faster than multiplying a and b |
|---|
| 1060 | first and adding c to the result. |
|---|
| 1061 | |
|---|
| 1062 | INPUT: |
|---|
| 1063 | a -- FiniteField_givaroElement |
|---|
| 1064 | b -- FiniteField_givaroElement |
|---|
| 1065 | c -- FiniteField_givaroElement |
|---|
| 1066 | |
|---|
| 1067 | EXAMPLE: |
|---|
| 1068 | sage: k.<a> = GF(2**8) |
|---|
| 1069 | sage: k.a_times_b_plus_c(a,a,k(1)) |
|---|
| 1070 | a^2 + 1 |
|---|
| 1071 | """ |
|---|
| 1072 | cdef int r |
|---|
| 1073 | |
|---|
| 1074 | r = self.objectptr.axpy(r, a.element, b.element, c.element) |
|---|
| 1075 | return make_FiniteField_givaroElement(self,r) |
|---|
| 1076 | |
|---|
| 1077 | def a_times_b_minus_c(FiniteField_givaro self,FiniteField_givaroElement a, FiniteField_givaroElement b, FiniteField_givaroElement c): |
|---|
| 1078 | """ |
|---|
| 1079 | Return r = a*b - c. |
|---|
| 1080 | |
|---|
| 1081 | INPUT: |
|---|
| 1082 | a -- FiniteField_givaroElement |
|---|
| 1083 | b -- FiniteField_givaroElement |
|---|
| 1084 | c -- FiniteField_givaroElement |
|---|
| 1085 | |
|---|
| 1086 | EXAMPLE: |
|---|
| 1087 | sage: k.<a> = GF(3**3) |
|---|
| 1088 | sage: k.a_times_b_minus_c(a,a,k(1)) |
|---|
| 1089 | a^2 + 2 |
|---|
| 1090 | """ |
|---|
| 1091 | cdef int r |
|---|
| 1092 | |
|---|
| 1093 | r = self.objectptr.axmy(r, a.element, b.element, c.element, ) |
|---|
| 1094 | return make_FiniteField_givaroElement(self,r) |
|---|
| 1095 | |
|---|
| 1096 | def c_minus_a_times_b(FiniteField_givaro self,FiniteField_givaroElement a, |
|---|
| 1097 | FiniteField_givaroElement b, FiniteField_givaroElement c): |
|---|
| 1098 | """ |
|---|
| 1099 | Return r = c - a*b. |
|---|
| 1100 | |
|---|
| 1101 | INPUT: |
|---|
| 1102 | a -- FiniteField_givaroElement |
|---|
| 1103 | b -- FiniteField_givaroElement |
|---|
| 1104 | c -- FiniteField_givaroElement |
|---|
| 1105 | |
|---|
| 1106 | EXAMPLE: |
|---|
| 1107 | sage: k.<a> = GF(3**3) |
|---|
| 1108 | sage: k.c_minus_a_times_b(a,a,k(1)) |
|---|
| 1109 | 2*a^2 + 1 |
|---|
| 1110 | """ |
|---|
| 1111 | cdef int r |
|---|
| 1112 | |
|---|
| 1113 | r = self.objectptr.amxy(r , a.element, b.element, c.element, ) |
|---|
| 1114 | return make_FiniteField_givaroElement(self,r) |
|---|
| 1115 | |
|---|
| 1116 | def __reduce__(FiniteField_givaro self): |
|---|
| 1117 | """ |
|---|
| 1118 | Pickle self: |
|---|
| 1119 | |
|---|
| 1120 | EXAMPLE: |
|---|
| 1121 | sage: k.<a> = GF(2**8) |
|---|
| 1122 | sage: loads(dumps(k)) == k |
|---|
| 1123 | True |
|---|
| 1124 | """ |
|---|
| 1125 | if self._array is None: |
|---|
| 1126 | cache = 0 |
|---|
| 1127 | else: |
|---|
| 1128 | cache = 1 |
|---|
| 1129 | |
|---|
| 1130 | return sage.rings.finite_field_givaro.unpickle_FiniteField_givaro, \ |
|---|
| 1131 | (self.order_c(),(self.variable_name(),), |
|---|
| 1132 | map(int,list(self.modulus())),int(self.repr),int(self._array is not None)) |
|---|
| 1133 | |
|---|
| 1134 | def unpickle_FiniteField_givaro(order,variable_name,modulus,rep,cache): |
|---|
| 1135 | from sage.rings.arith import is_prime |
|---|
| 1136 | |
|---|
| 1137 | if rep == 0: |
|---|
| 1138 | rep = 'poly' |
|---|
| 1139 | elif rep == 1: |
|---|
| 1140 | rep = 'log' |
|---|
| 1141 | elif rep == 2: |
|---|
| 1142 | rep = 'int' |
|---|
| 1143 | |
|---|
| 1144 | if not is_prime(order): |
|---|
| 1145 | return FiniteField_givaro(order,variable_name,modulus,rep,cache=cache) |
|---|
| 1146 | else: |
|---|
| 1147 | return FiniteField_givaro(order,cache=cache) |
|---|
| 1148 | |
|---|
| 1149 | cdef class FiniteField_givaro_iterator: |
|---|
| 1150 | """ |
|---|
| 1151 | Iterator over FiniteField_givaro elements of degree 1. We iterate |
|---|
| 1152 | over fields of higher degree using the VectorSpace iterator. |
|---|
| 1153 | |
|---|
| 1154 | EXAMPLES: |
|---|
| 1155 | sage: for x in GF(2^2,'a'): print x |
|---|
| 1156 | 0 |
|---|
| 1157 | a |
|---|
| 1158 | a + 1 |
|---|
| 1159 | 1 |
|---|
| 1160 | """ |
|---|
| 1161 | |
|---|
| 1162 | def __init__(self, FiniteField_givaro parent): |
|---|
| 1163 | self._parent = parent |
|---|
| 1164 | self.iterator = -1 |
|---|
| 1165 | |
|---|
| 1166 | def __next__(self): |
|---|
| 1167 | """ |
|---|
| 1168 | """ |
|---|
| 1169 | |
|---|
| 1170 | self.iterator=self.iterator+1 |
|---|
| 1171 | |
|---|
| 1172 | if self.iterator==self._parent.order_c(): |
|---|
| 1173 | self.iterator = -1 |
|---|
| 1174 | raise StopIteration |
|---|
| 1175 | |
|---|
| 1176 | return make_FiniteField_givaroElement(self._parent,self.iterator) |
|---|
| 1177 | |
|---|
| 1178 | def __repr__(self): |
|---|
| 1179 | return "Iterator over %s"%self._parent |
|---|
| 1180 | |
|---|
| 1181 | cdef FiniteField_givaro_copy(FiniteField_givaro orig): |
|---|
| 1182 | cdef FiniteField_givaro copy |
|---|
| 1183 | copy = FiniteField_givaro(orig.characteristic()**orig.degree()) |
|---|
| 1184 | delete(copy.objectptr) |
|---|
| 1185 | copy.objectptr = gfq_factorycopy(gfq_deref(orig.objectptr)) |
|---|
| 1186 | copy._zero_element = make_FiniteField_givaroElement(copy,copy.objectptr.zero) |
|---|
| 1187 | copy._one_element = make_FiniteField_givaroElement(copy,copy.objectptr.one) |
|---|
| 1188 | |
|---|
| 1189 | return copy |
|---|
| 1190 | |
|---|
| 1191 | cdef class FiniteField_givaroElement(FiniteFieldElement): |
|---|
| 1192 | """ |
|---|
| 1193 | An element of a (Givaro) finite field. |
|---|
| 1194 | """ |
|---|
| 1195 | |
|---|
| 1196 | def __init__(FiniteField_givaroElement self, parent ): |
|---|
| 1197 | """ |
|---|
| 1198 | Initializes an element in parent. It's much better to use |
|---|
| 1199 | parent(<value>) or any specialized method of parent |
|---|
| 1200 | (one,zero,gen) instead. |
|---|
| 1201 | |
|---|
| 1202 | Alternatively you may provide a value which is directly |
|---|
| 1203 | assigned to this element. So the value must represent the |
|---|
| 1204 | log_g of the value you wish to assign. |
|---|
| 1205 | |
|---|
| 1206 | INPUT: |
|---|
| 1207 | parent -- base field |
|---|
| 1208 | |
|---|
| 1209 | OUTPUT: |
|---|
| 1210 | finite field element. |
|---|
| 1211 | """ |
|---|
| 1212 | self._parent = <ParentWithBase> parent # explicit case required for C++ |
|---|
| 1213 | self.element = 0 |
|---|
| 1214 | |
|---|
| 1215 | cdef FiniteField_givaroElement _new_c(self, int value): |
|---|
| 1216 | return make_FiniteField_givaroElement(parent_object(self), value) |
|---|
| 1217 | |
|---|
| 1218 | def __dealloc__(FiniteField_givaroElement self): |
|---|
| 1219 | pass |
|---|
| 1220 | |
|---|
| 1221 | def __repr__(FiniteField_givaroElement self): |
|---|
| 1222 | return (<FiniteField_givaro>self._parent)._element_repr(self) |
|---|
| 1223 | |
|---|
| 1224 | def parent(self): |
|---|
| 1225 | """ |
|---|
| 1226 | Return parent finite field. |
|---|
| 1227 | |
|---|
| 1228 | EXAMPLES: |
|---|
| 1229 | sage: k.<a> = GF(3^4); k |
|---|
| 1230 | Finite Field in a of size 3^4 |
|---|
| 1231 | sage: (a*a).parent() |
|---|
| 1232 | Finite Field in a of size 3^4 |
|---|
| 1233 | """ |
|---|
| 1234 | return (<FiniteField_givaro>self._parent) |
|---|
| 1235 | |
|---|
| 1236 | def __nonzero__(FiniteField_givaroElement self): |
|---|
| 1237 | r""" |
|---|
| 1238 | Return True if \code{self != k(0)}. |
|---|
| 1239 | |
|---|
| 1240 | EXAMPLES: |
|---|
| 1241 | sage: k.<a> = GF(3^4); k |
|---|
| 1242 | Finite Field in a of size 3^4 |
|---|
| 1243 | sage: a.is_zero() |
|---|
| 1244 | False |
|---|
| 1245 | sage: k(0).is_zero() |
|---|
| 1246 | True |
|---|
| 1247 | """ |
|---|
| 1248 | return not (<FiniteField_givaro>self._parent).objectptr.isZero(self.element) |
|---|
| 1249 | |
|---|
| 1250 | def is_one(FiniteField_givaroElement self): |
|---|
| 1251 | r""" |
|---|
| 1252 | Return True if \code{self == k(1)}. |
|---|
| 1253 | |
|---|
| 1254 | EXAMPLES: |
|---|
| 1255 | sage: k.<a> = GF(3^4); k |
|---|
| 1256 | Finite Field in a of size 3^4 |
|---|
| 1257 | sage: a.is_one() |
|---|
| 1258 | False |
|---|
| 1259 | sage: k(1).is_one() |
|---|
| 1260 | True |
|---|
| 1261 | """ |
|---|
| 1262 | return (<FiniteField_givaro>self._parent).objectptr.isOne(self.element) |
|---|
| 1263 | |
|---|
| 1264 | def is_unit(FiniteField_givaroElement self): |
|---|
| 1265 | """ |
|---|
| 1266 | Return True if self is nonzero, so it is a unit as an element of the |
|---|
| 1267 | finite field. |
|---|
| 1268 | |
|---|
| 1269 | EXAMPLES: |
|---|
| 1270 | sage: k.<a> = GF(3^4); k |
|---|
| 1271 | Finite Field in a of size 3^4 |
|---|
| 1272 | sage: a.is_unit() |
|---|
| 1273 | True |
|---|
| 1274 | sage: k(0).is_unit() |
|---|
| 1275 | False |
|---|
| 1276 | """ |
|---|
| 1277 | return not (<FiniteField_givaro>self._parent).objectptr.isZero(self.element) |
|---|
| 1278 | # **WARNING** Givaro seems to define unit to mean in the prime field, |
|---|
| 1279 | # which is totally wrong! It's a confusion with the underlying polynomial |
|---|
| 1280 | # representation maybe?? That's why the following is commented out. |
|---|
| 1281 | # return (<FiniteField_givaro>self._parent).objectptr.isunit(self.element) |
|---|
| 1282 | |
|---|
| 1283 | |
|---|
| 1284 | def is_square(FiniteField_givaroElement self): |
|---|
| 1285 | """ |
|---|
| 1286 | Return True if self is a square in self.parent() |
|---|
| 1287 | |
|---|
| 1288 | EXAMPLES: |
|---|
| 1289 | sage: k.<a> = GF(9); k |
|---|
| 1290 | Finite Field in a of size 3^2 |
|---|
| 1291 | sage: a.is_square() |
|---|
| 1292 | False |
|---|
| 1293 | sage: v = set([x^2 for x in k]) |
|---|
| 1294 | sage: [x.is_square() for x in v] |
|---|
| 1295 | [True, True, True, True, True] |
|---|
| 1296 | sage: [x.is_square() for x in k if not x in v] |
|---|
| 1297 | [False, False, False, False] |
|---|
| 1298 | |
|---|
| 1299 | ALGORITHM: |
|---|
| 1300 | Elements are stored as powers of generators, so we simply check |
|---|
| 1301 | to see if it is an even power of a generator. |
|---|
| 1302 | |
|---|
| 1303 | TESTS: |
|---|
| 1304 | sage: K = GF(27, 'a') |
|---|
| 1305 | sage: set([a*a for a in K]) == set([a for a in K if a.is_square()]) |
|---|
| 1306 | True |
|---|
| 1307 | sage: K = GF(25, 'a') |
|---|
| 1308 | sage: set([a*a for a in K]) == set([a for a in K if a.is_square()]) |
|---|
| 1309 | True |
|---|
| 1310 | sage: K = GF(16, 'a') |
|---|
| 1311 | sage: set([a*a for a in K]) == set([a for a in K if a.is_square()]) |
|---|
| 1312 | True |
|---|
| 1313 | """ |
|---|
| 1314 | cdef FiniteField_givaro field = <FiniteField_givaro>self._parent |
|---|
| 1315 | if field.objectptr.characteristic() == 2: |
|---|
| 1316 | return True |
|---|
| 1317 | elif self.element == field.objectptr.one: |
|---|
| 1318 | return True |
|---|
| 1319 | else: |
|---|
| 1320 | return self.element % 2 == 0 |
|---|
| 1321 | |
|---|
| 1322 | def sqrt(FiniteField_givaroElement self, all=False, extend=False): |
|---|
| 1323 | """ |
|---|
| 1324 | Return a square root of this finite field element in its |
|---|
| 1325 | parent, if there is one. Otherwise, raise a ValueError. |
|---|
| 1326 | |
|---|
| 1327 | EXAMPLES: |
|---|
| 1328 | sage: k.<a> = GF(7^2) |
|---|
| 1329 | sage: k(2).sqrt() |
|---|
| 1330 | 3 |
|---|
| 1331 | sage: k(3).sqrt() |
|---|
| 1332 | 2*a + 6 |
|---|
| 1333 | sage: k(3).sqrt()**2 |
|---|
| 1334 | 3 |
|---|
| 1335 | sage: k(4).sqrt() |
|---|
| 1336 | 2 |
|---|
| 1337 | sage: k.<a> = GF(7^3) |
|---|
| 1338 | sage: k(3).sqrt() |
|---|
| 1339 | Traceback (most recent call last): |
|---|
| 1340 | ... |
|---|
| 1341 | ValueError: must be a perfect square. |
|---|
| 1342 | |
|---|
| 1343 | ALGORITHM: |
|---|
| 1344 | Self is stored as $a^k$ for some generator $a$. |
|---|
| 1345 | Return $a^(k/2)$ for even $k$. |
|---|
| 1346 | |
|---|
| 1347 | TESTS: |
|---|
| 1348 | sage: K = GF(49, 'a') |
|---|
| 1349 | sage: all([a.sqrt()*a.sqrt() == a for a in K if a.is_square()]) |
|---|
| 1350 | True |
|---|
| 1351 | sage: K = GF(27, 'a') |
|---|
| 1352 | sage: all([a.sqrt()*a.sqrt() == a for a in K if a.is_square()]) |
|---|
| 1353 | True |
|---|
| 1354 | sage: K = GF(8, 'a') |
|---|
| 1355 | sage: all([a.sqrt()*a.sqrt() == a for a in K if a.is_square()]) |
|---|
| 1356 | True |
|---|
| 1357 | """ |
|---|
| 1358 | if all: |
|---|
| 1359 | a = self.sqrt() |
|---|
| 1360 | return [a, -a] if -a != a else [a] |
|---|
| 1361 | cdef FiniteField_givaro field = <FiniteField_givaro>self._parent |
|---|
| 1362 | if self.element == field.objectptr.one: |
|---|
| 1363 | return make_FiniteField_givaroElement(field, field.objectptr.one) |
|---|
| 1364 | elif self.element % 2 == 0: |
|---|
| 1365 | return make_FiniteField_givaroElement(field, self.element/2) |
|---|
| 1366 | elif field.objectptr.characteristic() == 2: |
|---|
| 1367 | return make_FiniteField_givaroElement(field, (field.objectptr.cardinality() - 1 + self.element)/2) |
|---|
| 1368 | elif extend: |
|---|
| 1369 | raise NotImplementedError # TODO: fix this once we have nested embeddings of finite fields |
|---|
| 1370 | else: |
|---|
| 1371 | raise ValueError, "must be a perfect square." |
|---|
| 1372 | |
|---|
| 1373 | cdef ModuleElement _add_c_impl(self, ModuleElement right): |
|---|
| 1374 | """ |
|---|
| 1375 | Add two elements. |
|---|
| 1376 | |
|---|
| 1377 | EXAMPLE: |
|---|
| 1378 | sage: k.<b> = GF(9**2) |
|---|
| 1379 | sage: b^10 + 2*b |
|---|
| 1380 | 2*b^3 + 2*b^2 + 2*b + 1 |
|---|
| 1381 | """ |
|---|
| 1382 | cdef int r |
|---|
| 1383 | r = parent_object(self).objectptr.add(r, self.element , |
|---|
| 1384 | (<FiniteField_givaroElement>right).element ) |
|---|
| 1385 | return make_FiniteField_givaroElement(parent_object(self),r) |
|---|
| 1386 | |
|---|
| 1387 | cdef RingElement _mul_c_impl(self, RingElement right): |
|---|
| 1388 | """ |
|---|
| 1389 | Multiply two elements: |
|---|
| 1390 | |
|---|
| 1391 | EXAMPLE: |
|---|
| 1392 | sage: k.<c> = GF(7**4) |
|---|
| 1393 | sage: 3*c |
|---|
| 1394 | 3*c |
|---|
| 1395 | sage: c*c |
|---|
| 1396 | c^2 |
|---|
| 1397 | """ |
|---|
| 1398 | cdef int r |
|---|
| 1399 | r = parent_object(self).objectptr.mul(r, self.element, |
|---|
| 1400 | (<FiniteField_givaroElement>right).element) |
|---|
| 1401 | return make_FiniteField_givaroElement(parent_object(self),r) |
|---|
| 1402 | |
|---|
| 1403 | cdef RingElement _div_c_impl(self, RingElement right): |
|---|
| 1404 | """ |
|---|
| 1405 | Divide two elements |
|---|
| 1406 | |
|---|
| 1407 | EXAMPLE: |
|---|
| 1408 | sage: k.<g> = GF(2**8) |
|---|
| 1409 | sage: g/g |
|---|
| 1410 | 1 |
|---|
| 1411 | |
|---|
| 1412 | sage: k(1) / k(0) |
|---|
| 1413 | Traceback (most recent call last): |
|---|
| 1414 | ... |
|---|
| 1415 | ZeroDivisionError: division by zero in finite field. |
|---|
| 1416 | """ |
|---|
| 1417 | cdef int r |
|---|
| 1418 | if (<FiniteField_givaroElement>right).element == 0: |
|---|
| 1419 | raise ZeroDivisionError, 'division by zero in finite field.' |
|---|
| 1420 | r = parent_object(self).objectptr.div(r, self.element, |
|---|
| 1421 | (<FiniteField_givaroElement>right).element) |
|---|
| 1422 | return make_FiniteField_givaroElement(parent_object(self),r) |
|---|
| 1423 | |
|---|
| 1424 | cdef ModuleElement _sub_c_impl(self, ModuleElement right): |
|---|
| 1425 | """ |
|---|
| 1426 | Subtract two elements |
|---|
| 1427 | |
|---|
| 1428 | EXAMPLE: |
|---|
| 1429 | sage: k.<a> = GF(3**4) |
|---|
| 1430 | sage: k(3) - k(1) |
|---|
| 1431 | 2 |
|---|
| 1432 | sage: 2*a - a^2 |
|---|
| 1433 | 2*a^2 + 2*a |
|---|
| 1434 | """ |
|---|
| 1435 | cdef int r |
|---|
| 1436 | r = parent_object(self).objectptr.sub(r, self.element, |
|---|
| 1437 | (<FiniteField_givaroElement>right).element) |
|---|
| 1438 | return make_FiniteField_givaroElement(parent_object(self),r) |
|---|
| 1439 | |
|---|
| 1440 | def __neg__(FiniteField_givaroElement self): |
|---|
| 1441 | """ |
|---|
| 1442 | Negative of an element. |
|---|
| 1443 | |
|---|
| 1444 | EXAMPLES: |
|---|
| 1445 | sage: k.<a> = GF(9); k |
|---|
| 1446 | Finite Field in a of size 3^2 |
|---|
| 1447 | sage: -a |
|---|
| 1448 | 2*a |
|---|
| 1449 | """ |
|---|
| 1450 | cdef int r |
|---|
| 1451 | |
|---|
| 1452 | r = (<FiniteField_givaro>self._parent).objectptr.neg(r, self.element) |
|---|
| 1453 | return make_FiniteField_givaroElement((<FiniteField_givaro>self._parent),r) |
|---|
| 1454 | |
|---|
| 1455 | def __invert__(FiniteField_givaroElement self): |
|---|
| 1456 | """ |
|---|
| 1457 | Return the multiplicative inverse of an element. |
|---|
| 1458 | |
|---|
| 1459 | EXAMPLES: |
|---|
| 1460 | sage: k.<a> = GF(9); k |
|---|
| 1461 | Finite Field in a of size 3^2 |
|---|
| 1462 | sage: ~a |
|---|
| 1463 | a + 2 |
|---|
| 1464 | sage: ~a*a |
|---|
| 1465 | 1 |
|---|
| 1466 | """ |
|---|
| 1467 | cdef int r |
|---|
| 1468 | |
|---|
| 1469 | (<FiniteField_givaro>self._parent).objectptr.inv(r, self.element) |
|---|
| 1470 | return make_FiniteField_givaroElement((<FiniteField_givaro>self._parent),r) |
|---|
| 1471 | |
|---|
| 1472 | def __pow__(FiniteField_givaroElement self, exp, other): |
|---|
| 1473 | """ |
|---|
| 1474 | EXAMPLE: |
|---|
| 1475 | sage: K.<a> = GF(3^3, 'a') |
|---|
| 1476 | sage: a^3 == a*a*a |
|---|
| 1477 | True |
|---|
| 1478 | sage: b = a+1 |
|---|
| 1479 | sage: b^5 == b^2 * b^3 |
|---|
| 1480 | True |
|---|
| 1481 | sage: b^(-1) == 1/b |
|---|
| 1482 | True |
|---|
| 1483 | sage: b = K(-1) |
|---|
| 1484 | sage: b^2 == 1 |
|---|
| 1485 | True |
|---|
| 1486 | |
|---|
| 1487 | ALGORITHM: |
|---|
| 1488 | Givaro objects are stored as integers $i$ such that $self=a^i$, where |
|---|
| 1489 | $a$ is a generator of $K$ (though necissarily the one returned by K.gens()). |
|---|
| 1490 | Now it is trivial to compute $(a^i)^exp = a^(i*exp)$, and reducing the exponent |
|---|
| 1491 | mod the multiplicative order of $K$. |
|---|
| 1492 | |
|---|
| 1493 | AUTHOR: |
|---|
| 1494 | Robert Bradshaw |
|---|
| 1495 | """ |
|---|
| 1496 | _exp = int(exp) |
|---|
| 1497 | if _exp != exp: |
|---|
| 1498 | raise ValueError, "exponent must be an integer" |
|---|
| 1499 | exp = _exp |
|---|
| 1500 | |
|---|
| 1501 | cdef int r |
|---|
| 1502 | cdef int order |
|---|
| 1503 | cdef FiniteField_givaro field |
|---|
| 1504 | field = <FiniteField_givaro>self._parent |
|---|
| 1505 | |
|---|
| 1506 | if (field.objectptr).isOne(self.element): |
|---|
| 1507 | return self |
|---|
| 1508 | |
|---|
| 1509 | elif exp == 0: |
|---|
| 1510 | if (field.objectptr).isZero(self.element): |
|---|
| 1511 | raise ArithmeticError, "0^0 is undefined." |
|---|
| 1512 | return make_FiniteField_givaroElement(field, field.objectptr.one) |
|---|
| 1513 | |
|---|
| 1514 | elif (field.objectptr).isZero(self.element): |
|---|
| 1515 | return make_FiniteField_givaroElement(field, field.objectptr.zero) |
|---|
| 1516 | |
|---|
| 1517 | order = (field.order_c()-1) |
|---|
| 1518 | exp = exp % order |
|---|
| 1519 | |
|---|
| 1520 | r = exp |
|---|
| 1521 | if r == 0: |
|---|
| 1522 | return make_FiniteField_givaroElement(field, field.objectptr.one) |
|---|
| 1523 | |
|---|
| 1524 | r = (r * self.element) % order |
|---|
| 1525 | if r < 0: |
|---|
| 1526 | r = r + order |
|---|
| 1527 | if r == 0: |
|---|
| 1528 | return make_FiniteField_givaroElement(field, field.objectptr.one) |
|---|
| 1529 | |
|---|
| 1530 | return make_FiniteField_givaroElement(field, r) |
|---|
| 1531 | |
|---|
| 1532 | |
|---|
| 1533 | def __richcmp__(left, right, int op): |
|---|
| 1534 | return (<Element>left)._richcmp(right, op) |
|---|
| 1535 | cdef int _cmp_c_impl(left, Element right) except -2: |
|---|
| 1536 | """ |
|---|
| 1537 | Comparison of finite field elements is performed by comparing |
|---|
| 1538 | their underlying int representation. |
|---|
| 1539 | |
|---|
| 1540 | EXAMPLES: |
|---|
| 1541 | sage: k.<a> = GF(9); k |
|---|
| 1542 | Finite Field in a of size 3^2 |
|---|
| 1543 | sage: a < a^2 |
|---|
| 1544 | True |
|---|
| 1545 | sage: a^2 < a |
|---|
| 1546 | False |
|---|
| 1547 | """ |
|---|
| 1548 | cdef FiniteField_givaro F |
|---|
| 1549 | F = left._parent |
|---|
| 1550 | |
|---|
| 1551 | return cmp(F.log_to_int(left.element), F.log_to_int((<FiniteField_givaroElement>right).element) ) |
|---|
| 1552 | |
|---|
| 1553 | def __int__(FiniteField_givaroElement self): |
|---|
| 1554 | """ |
|---|
| 1555 | Return the int representation of self. When self is in the |
|---|
| 1556 | prime subfield, the integer returned is equal to self and not |
|---|
| 1557 | to \code{log_repr}. |
|---|
| 1558 | |
|---|
| 1559 | Elements of this field are represented as ints in as follows: |
|---|
| 1560 | for $e \in \FF_p[x]$ with $e = a_0 + a_1x + a_2x^2 + \cdots $, $e$ is |
|---|
| 1561 | represented as: $n= a_0 + a_1 p + a_2 p^2 + \cdots$. |
|---|
| 1562 | |
|---|
| 1563 | EXAMPLES: |
|---|
| 1564 | sage: k.<b> = GF(5^2); k |
|---|
| 1565 | Finite Field in b of size 5^2 |
|---|
| 1566 | sage: int(k(4)) |
|---|
| 1567 | 4 |
|---|
| 1568 | sage: int(b) |
|---|
| 1569 | 5 |
|---|
| 1570 | sage: type(int(b)) |
|---|
| 1571 | <type 'int'> |
|---|
| 1572 | """ |
|---|
| 1573 | return (<FiniteField_givaro>self._parent).log_to_int(self.element) |
|---|
| 1574 | |
|---|
| 1575 | |
|---|
| 1576 | def log_to_int(FiniteField_givaroElement self): |
|---|
| 1577 | r""" |
|---|
| 1578 | Returns the int representation of self, as a SAGE integer. Use |
|---|
| 1579 | int(self) to directly get a Python int. |
|---|
| 1580 | |
|---|
| 1581 | Elements of this field are represented as ints in as follows: |
|---|
| 1582 | for $e \in \FF_p[x]$ with $e = a_0 + a_1x + a_2x^2 + \cdots $, $e$ is |
|---|
| 1583 | represented as: $n= a_0 + a_1 p + a_2 p^2 + \cdots$. |
|---|
| 1584 | |
|---|
| 1585 | EXAMPLES: |
|---|
| 1586 | sage: k.<b> = GF(5^2); k |
|---|
| 1587 | Finite Field in b of size 5^2 |
|---|
| 1588 | sage: k(4).log_to_int() |
|---|
| 1589 | 4 |
|---|
| 1590 | sage: b.log_to_int() |
|---|
| 1591 | 5 |
|---|
| 1592 | sage: type(b.log_to_int()) |
|---|
| 1593 | <type 'sage.rings.integer.Integer'> |
|---|
| 1594 | """ |
|---|
| 1595 | return Integer((<FiniteField_givaro>self._parent).log_to_int(self.element)) |
|---|
| 1596 | |
|---|
| 1597 | def log(FiniteField_givaroElement self, base): |
|---|
| 1598 | """ |
|---|
| 1599 | Return the log to the base b of self, i.e., an integer n |
|---|
| 1600 | such that b^n = self. |
|---|
| 1601 | |
|---|
| 1602 | WARNING: TODO -- This is currently implemented by solving the discrete |
|---|
| 1603 | log problem -- which shouldn't be needed because of how finit field |
|---|
| 1604 | elements are represented. |
|---|
| 1605 | |
|---|
| 1606 | EXAMPLES: |
|---|
| 1607 | sage: k.<b> = GF(5^2); k |
|---|
| 1608 | Finite Field in b of size 5^2 |
|---|
| 1609 | sage: a = b^7 |
|---|
| 1610 | sage: a.log(b) |
|---|
| 1611 | 7 |
|---|
| 1612 | """ |
|---|
| 1613 | q = (<FiniteField_givaro> self.parent()).order_c() - 1 |
|---|
| 1614 | b = self.parent()(base) |
|---|
| 1615 | return sage.rings.arith.discrete_log_generic(self, b, q) |
|---|
| 1616 | |
|---|
| 1617 | def int_repr(FiniteField_givaroElement self): |
|---|
| 1618 | r""" |
|---|
| 1619 | Return the sring representation of self as an int (as returned |
|---|
| 1620 | by \code{log_to_int}). |
|---|
| 1621 | |
|---|
| 1622 | EXAMPLES: |
|---|
| 1623 | sage: k.<b> = GF(5^2); k |
|---|
| 1624 | Finite Field in b of size 5^2 |
|---|
| 1625 | sage: (b+1).int_repr() |
|---|
| 1626 | '6' |
|---|
| 1627 | """ |
|---|
| 1628 | return (<FiniteField_givaro>self._parent)._element_int_repr(self) |
|---|
| 1629 | |
|---|
| 1630 | def log_repr(FiniteField_givaroElement self): |
|---|
| 1631 | r""" |
|---|
| 1632 | Return the log representation of self as a string. See the |
|---|
| 1633 | documentation of the \code{_element_log_repr} function of the |
|---|
| 1634 | parent field. |
|---|
| 1635 | |
|---|
| 1636 | EXAMPLES: |
|---|
| 1637 | sage: k.<b> = GF(5^2); k |
|---|
| 1638 | Finite Field in b of size 5^2 |
|---|
| 1639 | sage: (b+2).log_repr() |
|---|
| 1640 | '3' |
|---|
| 1641 | """ |
|---|
| 1642 | return (<FiniteField_givaro>self._parent)._element_log_repr(self) |
|---|
| 1643 | |
|---|
| 1644 | def poly_repr(FiniteField_givaroElement self): |
|---|
| 1645 | r""" |
|---|
| 1646 | Return representation of this finite field element as a polynomial |
|---|
| 1647 | in the generator. |
|---|
| 1648 | |
|---|
| 1649 | EXAMPLES: |
|---|
| 1650 | sage: k.<b> = GF(5^2); k |
|---|
| 1651 | Finite Field in b of size 5^2 |
|---|
| 1652 | sage: (b+2).poly_repr() |
|---|
| 1653 | 'b + 2' |
|---|
| 1654 | """ |
|---|
| 1655 | return (<FiniteField_givaro>self._parent)._element_poly_repr(self) |
|---|
| 1656 | |
|---|
| 1657 | def polynomial(FiniteField_givaroElement self, name=None): |
|---|
| 1658 | """ |
|---|
| 1659 | Return self viewed as a polynomial over self.parent().prime_subfield(). |
|---|
| 1660 | |
|---|
| 1661 | EXAMPLES: |
|---|
| 1662 | sage: k.<b> = GF(5^2); k |
|---|
| 1663 | Finite Field in b of size 5^2 |
|---|
| 1664 | sage: f = (b^2+1).polynomial(); f |
|---|
| 1665 | b + 4 |
|---|
| 1666 | sage: type(f) |
|---|
| 1667 | <class 'sage.rings.polynomial.polynomial_element_generic.Polynomial_dense_mod_p'> |
|---|
| 1668 | sage: parent(f) |
|---|
| 1669 | Univariate Polynomial Ring in b over Finite Field of size 5 |
|---|
| 1670 | """ |
|---|
| 1671 | cdef FiniteField_givaro F |
|---|
| 1672 | F = self._parent |
|---|
| 1673 | quo = F.log_to_int(self.element) |
|---|
| 1674 | b = int(F.characteristic()) |
|---|
| 1675 | ret = [] |
|---|
| 1676 | for i in range(F.degree()): |
|---|
| 1677 | coeff = quo%b |
|---|
| 1678 | ret.append(coeff) |
|---|
| 1679 | quo = quo/b |
|---|
| 1680 | if not name is None and F.variable_name() != name: |
|---|
| 1681 | from sage.rings.polynomial.polynomial_ring import PolynomialRing |
|---|
| 1682 | return PolynomialRing(F.prime_subfield_C(), name)(ret) |
|---|
| 1683 | else: |
|---|
| 1684 | return F.polynomial_ring()(ret) |
|---|
| 1685 | |
|---|
| 1686 | def _latex_(FiniteField_givaroElement self): |
|---|
| 1687 | r""" |
|---|
| 1688 | Return the latex representation of self, which is just the |
|---|
| 1689 | latex representation of the polynomial representation of self. |
|---|
| 1690 | |
|---|
| 1691 | EXAMPLES: |
|---|
| 1692 | sage: k.<b> = GF(5^2); k |
|---|
| 1693 | Finite Field in b of size 5^2 |
|---|
| 1694 | sage: b._latex_() |
|---|
| 1695 | 'b' |
|---|
| 1696 | sage: (b^2+1)._latex_() |
|---|
| 1697 | 'b + 4' |
|---|
| 1698 | """ |
|---|
| 1699 | if (<FiniteField_givaro>self._parent).degree()>1: |
|---|
| 1700 | return self.polynomial()._latex_() |
|---|
| 1701 | else: |
|---|
| 1702 | return str(self) |
|---|
| 1703 | |
|---|
| 1704 | def _finite_field_ext_pari_element(FiniteField_givaroElement self, k=None): |
|---|
| 1705 | """ |
|---|
| 1706 | Return an element of k supposed to match this element. No |
|---|
| 1707 | checks if k equals self.parent() are performed. |
|---|
| 1708 | |
|---|
| 1709 | INPUT: |
|---|
| 1710 | k -- (optional) FiniteField_ext_pari |
|---|
| 1711 | |
|---|
| 1712 | OUTPUT: |
|---|
| 1713 | k.gen()^(self.log_repr()) |
|---|
| 1714 | |
|---|
| 1715 | EXAMPLES: |
|---|
| 1716 | sage: S.<b> = GF(5^2); S |
|---|
| 1717 | Finite Field in b of size 5^2 |
|---|
| 1718 | sage: b.charpoly('x') |
|---|
| 1719 | x^2 + 4*x + 2 |
|---|
| 1720 | sage: P = S._finite_field_ext_pari_(); type(P) |
|---|
| 1721 | <class 'sage.rings.finite_field.FiniteField_ext_pari'> |
|---|
| 1722 | sage: c = b._finite_field_ext_pari_element(P); c |
|---|
| 1723 | b |
|---|
| 1724 | sage: type(c) |
|---|
| 1725 | <class 'sage.rings.finite_field_element.FiniteField_ext_pariElement'> |
|---|
| 1726 | sage: c.charpoly('x') |
|---|
| 1727 | x^2 + 4*x + 2 |
|---|
| 1728 | |
|---|
| 1729 | The PARI field is automatically determined if it is not given: |
|---|
| 1730 | sage: d = b._finite_field_ext_pari_element(); d |
|---|
| 1731 | b |
|---|
| 1732 | sage: type(d) |
|---|
| 1733 | <class 'sage.rings.finite_field_element.FiniteField_ext_pariElement'> |
|---|
| 1734 | """ |
|---|
| 1735 | if k is None: |
|---|
| 1736 | k = (<FiniteField_givaro>self._parent)._finite_field_ext_pari_() |
|---|
| 1737 | elif not isinstance(k, finite_field.FiniteField_ext_pari): |
|---|
| 1738 | raise TypeError, "k must be a pari finite field." |
|---|
| 1739 | |
|---|
| 1740 | variable = k.gen()._pari_() |
|---|
| 1741 | |
|---|
| 1742 | quo = int(self) |
|---|
| 1743 | b = int((<FiniteField_givaro>self._parent).characteristic()) |
|---|
| 1744 | |
|---|
| 1745 | ret = k._pari_one() - k._pari_one() # TODO -- weird |
|---|
| 1746 | i = 0 |
|---|
| 1747 | while quo!=0: |
|---|
| 1748 | coeff = quo%b |
|---|
| 1749 | if coeff != 0: |
|---|
| 1750 | ret = coeff * variable ** i + ret |
|---|
| 1751 | quo = quo/b |
|---|
| 1752 | i = i+1 |
|---|
| 1753 | return k(ret) |
|---|
| 1754 | |
|---|
| 1755 | def _pari_init_(FiniteField_givaroElement self, var=None): |
|---|
| 1756 | """ |
|---|
| 1757 | Return string that when evealuated in PARI defines this element. |
|---|
| 1758 | |
|---|
| 1759 | EXAMPLES: |
|---|
| 1760 | sage: S.<b> = GF(5^2); S |
|---|
| 1761 | Finite Field in b of size 5^2 |
|---|
| 1762 | sage: b._pari_init_() |
|---|
| 1763 | 'Mod(b, Mod(1, 5)*b^2 + Mod(4, 5)*b + Mod(2, 5))' |
|---|
| 1764 | sage: (2*b+3)._pari_init_() |
|---|
| 1765 | 'Mod(2*b + 3, Mod(1, 5)*b^2 + Mod(4, 5)*b + Mod(2, 5))' |
|---|
| 1766 | """ |
|---|
| 1767 | g = (parent_object(self))._finite_field_ext_pari_modulus_as_str() |
|---|
| 1768 | f = self.poly_repr() |
|---|
| 1769 | s = 'Mod(%s, %s)'%(f, g) |
|---|
| 1770 | if var is None: |
|---|
| 1771 | return s |
|---|
| 1772 | return s.replace(self.parent().variable_name(), var) |
|---|
| 1773 | |
|---|
| 1774 | def _pari_(FiniteField_givaroElement self, var=None): |
|---|
| 1775 | return pari(self._pari_init_(var)) |
|---|
| 1776 | |
|---|
| 1777 | |
|---|
| 1778 | ## variable = k.gen()._pari_() |
|---|
| 1779 | ## quo = int(self) |
|---|
| 1780 | ## b = (parent_object(self)).characteristic() |
|---|
| 1781 | ## ret = k._pari_one() - k._pari_one() # there is no pari_zero |
|---|
| 1782 | ## i = 0 |
|---|
| 1783 | ## while quo!=0: |
|---|
| 1784 | ## coeff = quo%b |
|---|
| 1785 | ## if coeff != 0: |
|---|
| 1786 | ## ret = coeff * variable ** i + ret |
|---|
| 1787 | ## quo = quo/b |
|---|
| 1788 | ## i = i+1 |
|---|
| 1789 | ## return ret |
|---|
| 1790 | |
|---|
| 1791 | def _magma_init_(self): |
|---|
| 1792 | """ |
|---|
| 1793 | Return a string representation of self that MAGMA can |
|---|
| 1794 | understand. |
|---|
| 1795 | |
|---|
| 1796 | """ |
|---|
| 1797 | km = self.parent()._magma_() |
|---|
| 1798 | vn = km.gen(1).name() |
|---|
| 1799 | return self.parent()._element_poly_repr(self,vn) |
|---|
| 1800 | |
|---|
| 1801 | def multiplicative_order(FiniteField_givaroElement self): |
|---|
| 1802 | """ |
|---|
| 1803 | Return the multiplicative order of this field element. |
|---|
| 1804 | |
|---|
| 1805 | EXAMPLES: |
|---|
| 1806 | sage: S.<b> = GF(5^2); S |
|---|
| 1807 | Finite Field in b of size 5^2 |
|---|
| 1808 | sage: b.multiplicative_order() |
|---|
| 1809 | 24 |
|---|
| 1810 | sage: (b^6).multiplicative_order() |
|---|
| 1811 | 4 |
|---|
| 1812 | """ |
|---|
| 1813 | # TODO -- I'm sure this can be made vastly faster |
|---|
| 1814 | # using how elements are represented as a power of the generator ?? |
|---|
| 1815 | |
|---|
| 1816 | # code copy'n'pasted from finite_field_element.py |
|---|
| 1817 | import sage.rings.arith |
|---|
| 1818 | |
|---|
| 1819 | if self.__multiplicative_order is not None: |
|---|
| 1820 | return self.__multiplicative_order |
|---|
| 1821 | else: |
|---|
| 1822 | if self.is_zero(): |
|---|
| 1823 | return ArithmeticError, "Multiplicative order of 0 not defined." |
|---|
| 1824 | n = (parent_object(self)).order_c() - 1 |
|---|
| 1825 | order = 1 |
|---|
| 1826 | for p, e in sage.rings.arith.factor(n): |
|---|
| 1827 | # Determine the power of p that divides the order. |
|---|
| 1828 | a = self**(n/(p**e)) |
|---|
| 1829 | while a != 1: |
|---|
| 1830 | order = order * p |
|---|
| 1831 | a = a**p |
|---|
| 1832 | self.__multiplicative_order = order |
|---|
| 1833 | return order |
|---|
| 1834 | |
|---|
| 1835 | def __copy__(self): |
|---|
| 1836 | """ |
|---|
| 1837 | Return a copy of this element. Actually just returns self, since |
|---|
| 1838 | finite field elements are immutable. |
|---|
| 1839 | |
|---|
| 1840 | EXAMPLES: |
|---|
| 1841 | sage: S.<b> = GF(5^2); S |
|---|
| 1842 | Finite Field in b of size 5^2 |
|---|
| 1843 | sage: c = copy(b); c |
|---|
| 1844 | b |
|---|
| 1845 | sage: c is b |
|---|
| 1846 | True |
|---|
| 1847 | sage: copy(5r) is 5r |
|---|
| 1848 | True |
|---|
| 1849 | """ |
|---|
| 1850 | return self |
|---|
| 1851 | |
|---|
| 1852 | def _gap_init_(FiniteField_givaroElement self): |
|---|
| 1853 | """ |
|---|
| 1854 | Return a string that evaluates to the GAP representation of |
|---|
| 1855 | this element. |
|---|
| 1856 | |
|---|
| 1857 | A NotImplementedError is raised if self.parent().modulus() is |
|---|
| 1858 | not a Conway polynomial, as the isomorphism of finite fields is |
|---|
| 1859 | not implemented yet. |
|---|
| 1860 | |
|---|
| 1861 | EXAMPLES: |
|---|
| 1862 | sage: S.<b> = GF(5^2); S |
|---|
| 1863 | Finite Field in b of size 5^2 |
|---|
| 1864 | sage: (4*b+3)._gap_init_() |
|---|
| 1865 | 'Z(25)^3' |
|---|
| 1866 | sage: S(gap('Z(25)^3')) |
|---|
| 1867 | 4*b + 3 |
|---|
| 1868 | """ |
|---|
| 1869 | #copied from finite_field_element.py |
|---|
| 1870 | cdef FiniteField_givaro F |
|---|
| 1871 | F = parent_object(self) |
|---|
| 1872 | if not F._is_conway: |
|---|
| 1873 | raise NotImplementedError, "conversion of (Givaro) finite field element to GAP not implemented except for fields defined by Conway polynomials." |
|---|
| 1874 | if F.order_c() > 65536: |
|---|
| 1875 | raise TypeError, "order (=%s) must be at most 65536."%F.order_c() |
|---|
| 1876 | if self == 0: |
|---|
| 1877 | return '0*Z(%s)'%F.order_c() |
|---|
| 1878 | assert F.degree() > 1 |
|---|
| 1879 | g = F.multiplicative_generator() |
|---|
| 1880 | n = self.log(g) |
|---|
| 1881 | return 'Z(%s)^%s'%(F.order_c(), n) |
|---|
| 1882 | |
|---|
| 1883 | def charpoly(FiniteField_givaroElement self, var): |
|---|
| 1884 | """ |
|---|
| 1885 | Return the characteristic polynomial of self as a polynomial with given variable. |
|---|
| 1886 | |
|---|
| 1887 | EXAMPLES: |
|---|
| 1888 | sage: k.<a> = GF(19^2) |
|---|
| 1889 | sage: parent(a) |
|---|
| 1890 | Finite Field in a of size 19^2 |
|---|
| 1891 | sage: a.charpoly('X') |
|---|
| 1892 | X^2 + 18*X + 2 |
|---|
| 1893 | sage: a^2 + 18*a + 2 |
|---|
| 1894 | 0 |
|---|
| 1895 | """ |
|---|
| 1896 | from sage.rings.polynomial.polynomial_ring import PolynomialRing |
|---|
| 1897 | R = PolynomialRing(parent_object(self).prime_subfield_C(), var) |
|---|
| 1898 | return R(self._pari_().charpoly('x').lift()) |
|---|
| 1899 | |
|---|
| 1900 | |
|---|
| 1901 | def norm(FiniteField_givaroElement self): |
|---|
| 1902 | """ |
|---|
| 1903 | Return the norm of self down to the prime subfield. |
|---|
| 1904 | |
|---|
| 1905 | This is the product of the Galois conjugates of self. |
|---|
| 1906 | |
|---|
| 1907 | EXAMPLES: |
|---|
| 1908 | sage: S.<b> = GF(5^2); S |
|---|
| 1909 | Finite Field in b of size 5^2 |
|---|
| 1910 | sage: b.norm() |
|---|
| 1911 | 2 |
|---|
| 1912 | sage: b.charpoly('t') |
|---|
| 1913 | t^2 + 4*t + 2 |
|---|
| 1914 | |
|---|
| 1915 | Next we consider a cubic extension: |
|---|
| 1916 | sage: S.<a> = GF(5^3); S |
|---|
| 1917 | Finite Field in a of size 5^3 |
|---|
| 1918 | sage: a.norm() |
|---|
| 1919 | 2 |
|---|
| 1920 | sage: a.charpoly('t') |
|---|
| 1921 | t^3 + 3*t + 3 |
|---|
| 1922 | sage: a * a^5 * (a^25) |
|---|
| 1923 | 2 |
|---|
| 1924 | """ |
|---|
| 1925 | f = self.charpoly('x') |
|---|
| 1926 | n = f[0] |
|---|
| 1927 | if f.degree() % 2 != 0: |
|---|
| 1928 | return -n |
|---|
| 1929 | else: |
|---|
| 1930 | return n |
|---|
| 1931 | |
|---|
| 1932 | def trace(FiniteField_givaroElement self): |
|---|
| 1933 | """ |
|---|
| 1934 | Return the trace of this element, which is the sum of the |
|---|
| 1935 | Galois conjugates. |
|---|
| 1936 | |
|---|
| 1937 | EXAMPLES: |
|---|
| 1938 | sage: S.<a> = GF(5^3); S |
|---|
| 1939 | Finite Field in a of size 5^3 |
|---|
| 1940 | sage: a.trace() |
|---|
| 1941 | 0 |
|---|
| 1942 | sage: a.charpoly('t') |
|---|
| 1943 | t^3 + 3*t + 3 |
|---|
| 1944 | sage: a + a^5 + a^25 |
|---|
| 1945 | 0 |
|---|
| 1946 | sage: z = a^2 + a + 1 |
|---|
| 1947 | sage: z.trace() |
|---|
| 1948 | 2 |
|---|
| 1949 | sage: z.charpoly('t') |
|---|
| 1950 | t^3 + 3*t^2 + 2*t + 2 |
|---|
| 1951 | sage: z + z^5 + z^25 |
|---|
| 1952 | 2 |
|---|
| 1953 | """ |
|---|
| 1954 | return parent_object(self).prime_subfield()(self._pari_().trace().lift()) |
|---|
| 1955 | |
|---|
| 1956 | def __hash__(FiniteField_givaroElement self): |
|---|
| 1957 | """ |
|---|
| 1958 | Return the hash of this finite field element. We hash the parent |
|---|
| 1959 | and the underlying integer representation of this element. |
|---|
| 1960 | |
|---|
| 1961 | EXAMPLES: |
|---|
| 1962 | sage: S.<a> = GF(5^3); S |
|---|
| 1963 | Finite Field in a of size 5^3 |
|---|
| 1964 | sage: hash(a) |
|---|
| 1965 | 5 |
|---|
| 1966 | """ |
|---|
| 1967 | return hash(self.log_to_int()) |
|---|
| 1968 | |
|---|
| 1969 | def vector(FiniteField_givaroElement self): |
|---|
| 1970 | """ |
|---|
| 1971 | Return a vector in self.parent().vector_space() matching self. |
|---|
| 1972 | |
|---|
| 1973 | EXAMPLES: |
|---|
| 1974 | sage: k.<a> = GF(2^4) |
|---|
| 1975 | sage: e = a^2 + 1 |
|---|
| 1976 | sage: v = e.vector() |
|---|
| 1977 | sage: v |
|---|
| 1978 | (1, 0, 1, 0) |
|---|
| 1979 | sage: k(v) |
|---|
| 1980 | a^2 + 1 |
|---|
| 1981 | |
|---|
| 1982 | sage: k.<a> = GF(3^4) |
|---|
| 1983 | sage: e = 2*a^2 + 1 |
|---|
| 1984 | sage: v = e.vector() |
|---|
| 1985 | sage: v |
|---|
| 1986 | (1, 0, 2, 0) |
|---|
| 1987 | sage: k(v) |
|---|
| 1988 | 2*a^2 + 1 |
|---|
| 1989 | |
|---|
| 1990 | """ |
|---|
| 1991 | cdef FiniteField_givaro k = <FiniteField_givaro>self._parent |
|---|
| 1992 | |
|---|
| 1993 | quo = k.log_to_int(self.element) |
|---|
| 1994 | b = int(k.characteristic()) |
|---|
| 1995 | |
|---|
| 1996 | ret = [] |
|---|
| 1997 | for i in range(k.degree()): |
|---|
| 1998 | coeff = quo%b |
|---|
| 1999 | ret.append(coeff) |
|---|
| 2000 | quo = quo/b |
|---|
| 2001 | return k.vector_space()(ret) |
|---|
| 2002 | |
|---|
| 2003 | def __reduce__(FiniteField_givaroElement self): |
|---|
| 2004 | """ |
|---|
| 2005 | Used for supporting pickling of finite field elements. |
|---|
| 2006 | |
|---|
| 2007 | EXAMPLE: |
|---|
| 2008 | sage: k = GF(2**8, 'a') |
|---|
| 2009 | sage: e = k.random_element() |
|---|
| 2010 | sage: loads(dumps(e)) == e |
|---|
| 2011 | True |
|---|
| 2012 | """ |
|---|
| 2013 | return unpickle_FiniteField_givaroElement,(parent_object(self),self.element) |
|---|
| 2014 | |
|---|
| 2015 | |
|---|
| 2016 | def unpickle_FiniteField_givaroElement(FiniteField_givaro parent, int x): |
|---|
| 2017 | return make_FiniteField_givaroElement(parent, x) |
|---|
| 2018 | |
|---|
| 2019 | cdef inline FiniteField_givaroElement make_FiniteField_givaroElement(FiniteField_givaro parent, int x): |
|---|
| 2020 | cdef FiniteField_givaroElement y |
|---|
| 2021 | cdef PyObject** w |
|---|
| 2022 | |
|---|
| 2023 | if parent._array is None: |
|---|
| 2024 | #y = FiniteField_givaroElement(parent) |
|---|
| 2025 | y = PY_NEW(FiniteField_givaroElement) |
|---|
| 2026 | y._parent = <ParentWithBase> parent |
|---|
| 2027 | y.element = x |
|---|
| 2028 | return y |
|---|
| 2029 | else: |
|---|
| 2030 | return <FiniteField_givaroElement>parent._array[x] |
|---|
| 2031 | |
|---|
| 2032 | def gap_to_givaro(x, F): |
|---|
| 2033 | """ |
|---|
| 2034 | INPUT: |
|---|
| 2035 | x -- gap finite field element |
|---|
| 2036 | F -- Givaro finite field |
|---|
| 2037 | OUTPUT: |
|---|
| 2038 | element of F |
|---|
| 2039 | |
|---|
| 2040 | EXAMPLES: |
|---|
| 2041 | sage: from sage.rings.finite_field_givaro import FiniteField_givaro |
|---|
| 2042 | sage: x = gap('Z(13)') |
|---|
| 2043 | sage: F = FiniteField_givaro(13) |
|---|
| 2044 | sage: F(x) |
|---|
| 2045 | 2 |
|---|
| 2046 | sage: F(gap('0*Z(13)')) |
|---|
| 2047 | 0 |
|---|
| 2048 | sage: F = FiniteField_givaro(13^2) |
|---|
| 2049 | sage: x = gap('Z(13)') |
|---|
| 2050 | sage: F(x) |
|---|
| 2051 | 2 |
|---|
| 2052 | sage: x = gap('Z(13^2)^3') |
|---|
| 2053 | sage: F(x) |
|---|
| 2054 | 12*a + 11 |
|---|
| 2055 | sage: F.multiplicative_generator()^3 |
|---|
| 2056 | 12*a + 11 |
|---|
| 2057 | |
|---|
| 2058 | AUTHOR: |
|---|
| 2059 | -- David Joyner and William Stein |
|---|
| 2060 | -- Martin Albrecht (copied from gap_to_sage) |
|---|
| 2061 | """ |
|---|
| 2062 | return gap_to_givaro_c(x,F) |
|---|
| 2063 | |
|---|
| 2064 | cdef gap_to_givaro_c(x, FiniteField_givaro F): |
|---|
| 2065 | s = str(x) |
|---|
| 2066 | if s[:2] == '0*': |
|---|
| 2067 | return F(0) |
|---|
| 2068 | i1 = s.index("(") |
|---|
| 2069 | i2 = s.index(")") |
|---|
| 2070 | q = eval(s[i1+1:i2].replace('^','**')) |
|---|
| 2071 | if q == F.order_c(): |
|---|
| 2072 | K = F |
|---|
| 2073 | else: |
|---|
| 2074 | K = finite_field.FiniteField(q,'a') |
|---|
| 2075 | if s.find(')^') == -1: |
|---|
| 2076 | e = 1 |
|---|
| 2077 | else: |
|---|
| 2078 | e = int(s[i2+2:]) |
|---|
| 2079 | |
|---|
| 2080 | if F.degree() == 1: |
|---|
| 2081 | g = int(sage.interfaces.gap.gap.eval('Int(Z(%s))'%q)) |
|---|
| 2082 | else: |
|---|
| 2083 | g = K.multiplicative_generator() |
|---|
| 2084 | return F(K(g**e)) |
|---|
| 2085 | |
|---|