3 # Compute properties of mathematical "fields" formed by taking
4 # Z/n (the whole numbers modulo some whole number n) and an
5 # irreducible polynomial (i.e., a polynomial with only complex zeros),
6 # e.g., Z/5 and X**2 + 2.
8 # The field is formed by taking all possible linear combinations of
9 # a set of d base vectors (where d is the degree of the polynomial).
11 # Note that this procedure doesn't yield a field for all combinations
12 # of n and p: it may well be that some numbers have more than one
13 # inverse and others have none. This is what we check.
15 # Remember that a field is a ring where each element has an inverse.
16 # A ring has commutative addition and multiplication, a zero and a one:
17 # 0*x = x*0 = 0, 0+x = x+0 = x, 1*x = x*1 = x. Also, the distributive
18 # property holds: a*(b+c) = a*b + b*c.
19 # (XXX I forget if this is an axiom or follows from the rules.)
24 # Example N and polynomial
27 P
= poly
.plus(poly
.one(0, 2), poly
.one(2, 1)) # 2 + x**2
30 # Return x modulo y. Returns >= 0 even if x < 0.
33 return divmod(x
, y
)[1]
36 # Normalize a polynomial modulo n and modulo p.
41 for i
in range(len(a
)): a
[i
] = mod(a
[i
], n
)
46 # Make a list of all n^d elements of the proposed field.
55 def make_elements(n
, d
):
56 if d
== 0: return [poly
.one(0, 0)]
57 sub
= make_elements(n
, d
-1)
61 all
.append(poly
.plus(a
, poly
.one(d
-1, i
)))
64 def make_inv(all
, n
, p
):
68 inv
.append(norm(poly
.times(a
, x
), n
, p
))
72 all
= make_elements(n
, len(p
)-1)
73 inv
= make_inv(all
, n
, p
)
78 if all1
== inv1
: print 'BINGO!'
85 if type(s
) <> type(''): s
= `s`
87 if n
>= width
: return s
88 return ' '*(width
- n
) + s
91 if type(s
) <> type(''): s
= `s`
93 if n
>= width
: return s
94 return s
+ ' '*(width
- n
)