4 The method is for obtaining the maximal order of a number field from a 5 subring generated by a root of a defining polynomial of the field. 7 - H.Cohen CCANT Algorithm 6.1.8 11 from __future__
import division
25 _log = logging.getLogger(
'nzmath.round2')
29 Z = rational.theIntegerRing
30 Q = rational.theRationalField
34 Return integral basis of the ring of integers of a field with its 35 discriminant. The field is given by a list of integers, which is 36 a polynomial of generating element theta. The polynomial ought to 37 be monic, in other word, the generating element ought to be an 40 The integral basis will be given as a list of rational vectors 41 with respect to theta. (In other functions, bases are returned in 44 minpoly_int = uniutil.polynomial(enumerate(minpoly_coeff), Z)
45 d = minpoly_int.discriminant()
48 for p, e
in squarefactors:
49 _log.debug(
"p = %d" % p)
50 omega = omega +
_p_maximal(p, e, minpoly_coeff)
52 G = omega.determinant()
53 return omega.get_rationals(), d * G**2
57 Return a list of square factors of disc (=discriminant). 63 fund_disc, absd = -1, -disc
65 fund_disc, absd = 1, disc
66 v2, absd = arith1.vp(absd, 2)
67 if squarefree.trivial_test_ternary(absd):
70 for p, e
in factor_misc.FactoredInteger(absd):
72 squareness, oddity = divmod(e, 2)
73 squarefactors.append((p, squareness))
78 if fund_disc & 3 == 1:
80 squareness, oddity = divmod(v2, 2)
81 squarefactors.append((2, squareness))
85 squarefactors.append((2, v2 >> 1))
90 squarefactors.append((2, (v2 - 2) >> 1))
95 Return p-maximal basis with some related informations. 100 minpoly_coeff: (intefer) list of coefficients of the minimal 104 finished, omega =
Dedekind(minpoly_coeff, p, e)
106 _log.info(
"Dedekind(%d)" % p)
110 minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
111 theminpoly = minpoly.to_field_polynomial()
112 n = theminpoly.degree()
113 q = p ** (arith1.log(n, p) + 1)
117 alpha, l =
_p_radical(omega, p, q, minpoly, n)
122 zeta =
_p_module(alpha, l, p, theminpoly)
129 omega2 = zeta / p + omega
130 if all(o1 == o2
for o1, o2
in zip(omega.basis, omega2.basis)):
139 Return module Ip with dimension of Ip/pO. 141 Ip is the radical of pO, or 142 Ip = {x in O | ~x in kernel f}, 143 where ~x is x mod pO, f is q(=p^e > n)-th powering, which in fact an 153 beta_p = base_p.supplementBasis()
157 omega_poly = omega.get_polynomials()
159 for j
in range(1, l + 1):
160 alpha_basis.append(omega.linear_combination([
_pull_back(c, p)
for c
in beta_p[j]]))
161 for j
in range(l + 1, n + 1):
162 alpha_basis.append(omega.linear_combination([
_pull_back(c, p) * p
for c
in beta_p[j]]))
168 Return the kernel of q-th powering, which is a linear map over Fp. 169 q is a power of p which exceeds n. 171 (omega_j^q (mod theminpoly) = \sum a_i_j omega_i a_i_j in Fp) 173 omega_poly = omega.get_polynomials()
174 denom = omega.denominator
175 theminpoly = minpoly.to_field_polynomial()
176 field_p = finitefield.FinitePrimeField.getInstance(p)
178 qpow = matrix.zeroMatrix(n, n, field_p)
181 omega_poly_j = uniutil.polynomial(enumerate(omega.basis[j]), Z)
182 omega_j_qpow = pow(omega_poly_j, q, minpoly)
183 redundancy = gcd.gcd(omega_j_qpow.content(), denom ** q)
184 omega_j_qpow = omega_j_qpow.coefficients_map(
lambda c: c // redundancy)
185 essential = denom ** q // redundancy
187 i = omega_j_qpow.degree()
188 a_ji = int(omega_j_qpow[i] / (omega_poly[i][i] * essential))
189 omega_j_qpow -= a_ji * (omega_poly[i] * essential)
190 if omega_j_qpow.degree() < i:
191 a_j[i] = field_p.createElement(a_ji)
193 _log.debug(
"%s / %d" % (str(omega_j_qpow), essential))
194 _log.debug(
"j = %d, a_ji = %s" % (j, a_ji))
195 raise ValueError(
"omega is not a basis")
196 qpow.setColumn(j + 1, a_j)
198 result = qpow.kernel()
200 _log.debug(
"(_k_q): trivial kernel")
201 return matrix.zeroMatrix(n, 1, field_p)
207 Return basis of Up/pO, where Up = {x in Ip | xIp \subset pIp}. 209 zeta = alpha.get_polynomials()[:l]
217 for k
in range(1, kernel.column + 1):
218 newzeta.append(sum(
_pull_back(c, p) * z
for (c, z)
in zip(kernel[k], zeta)))
220 n = theminpoly.degree()
229 for i
in range(len(zeta_list)):
230 zeta_list[i] = [c * p
for c
in zeta_list[i]]
232 _log.debug(
"denominator = %d" % denominator)
238 Return linear combination coefficients of tau_i = z_i * alpha[j], 239 which is congruent to 0 modulo theminpoly and pIp. 243 zeta_{j+1} = {z in zeta_j | z * alpha[j] (mod theminpoly) = 0 (mod pIp)} 245 n = theminpoly.degree()
247 assert n == len(alpha.basis)
248 alpha_basis = [tuple(b)
for b
in alpha.get_rationals()]
249 alpha_mat = matrix.createMatrix(n, alpha_basis, coeff_ring=Q)
250 alpha_poly = alpha.get_polynomials()
254 tau_i = zeta[i] * alpha_poly[j] % theminpoly
256 tau_mat = matrix.createMatrix(n, l, taus, coeff_ring=Q)
258 xi = alpha_mat.inverseImage(tau_mat)
260 field_p = finitefield.FinitePrimeField.getInstance(p)
261 xi_p = xi.map(field_p.createElement)
266 Return (finished or not, an order) 268 the Dedekind criterion 271 - minpoly_coeff: (integer) list of the minimal polynomial of theta. 272 - p, e: p**e divides the discriminant of the minimal polynomial. 274 n = len(minpoly_coeff) - 1
282 minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
285 for i
in range(1, m):
286 shift = shift.upshift_degree(1).pseudo_mod(minpoly)
290 return (m + 1 > e), updater + omega
294 Factor theminpoly modulo p, and return two values in a tuple. 295 We call gcd(square factors mod p, difference of minpoly and its modp) Z. 297 2) (minpoly mod p) / Z 299 Fp = finitefield.FinitePrimeField.getInstance(p)
300 theminpoly_p = uniutil.polynomial([(d, Fp.createElement(c))
for (d, c)
in enumerate(minpoly_coeff)], Fp)
301 modpfactors = theminpoly_p.factor()
302 mini_p = arith1.product([t
for (t, e)
in modpfactors])
303 quot_p = theminpoly_p.exact_division(mini_p)
306 minpoly = uniutil.polynomial(enumerate(minpoly_coeff), Z)
307 f_p =
_mod_p((mini * quot - minpoly).scalar_exact_division(p), p)
308 gcd = f_p.getRing().gcd
309 common_p =
gcd(
gcd(mini_p, quot_p), f_p)
310 uniq_p = theminpoly_p // common_p
313 return common_p.degree(), uniq
317 Return modulo p reduction of given integer coefficient polynomial. 322 return uniutil.polynomial(poly, finitefield.FinitePrimeField.getInstance(p))
326 Return minimal absolute mapping of given F_p coefficient polynomial. 329 p = poly_p.getCoefficientRing().char
332 return uniutil.polynomial(coeff, Z)
336 Return a list of given size consisting of coefficients of upoly 337 and possibly zeros padded. 339 return [upoly[i]
for i
in range(size)]
343 Return an integer which is a pull back of elem in Fp. 354 if result > (p >> 1):
360 Return integer object, which is equal to given elem, whose type is 361 either integer or rational number. 363 if isinstance(elem, (int, long)):
365 elif elem.denominator == 1:
366 return elem.numerator
368 raise ValueError(
"non integer: %s" % str(elem))
372 Return the default omega 379 Return i-th standard unit base 387 Return rational polynomial with given coefficients in ascending 390 return uniutil.polynomial(enumerate(coeffs), Q)
395 Represent basis of Z-module with denominator 399 basis is a list of integer sequences. 400 denominator is a common denominator of all bases. 403 ModuleWithDenominator([[1, 2], [4, 6]], 2) represents a module 418 Return a list of rational list, which is basis divided by 423 for base
in self.
basis:
429 Return a list of rational polynomials, which is made from basis 430 divided by denominator. 434 for base
in self.
basis:
441 Return sum of two modules. 443 denominator = gcd.lcm(self.
denominator, other.denominator)
445 assert row == other.dimension
446 column = self.
rank + other.rank
447 mat = matrix.createMatrix(row, column)
449 for i, base
in enumerate(self.
basis):
450 mat.setColumn(i + 1, [c * adjust
for c
in base])
451 adjust = denominator // other.denominator
452 for i, base
in enumerate(other.basis):
453 mat.setColumn(self.
rank + i + 1, [c * adjust
for c
in base])
456 hnf = mat.hermiteNormalForm()
460 while hnf.row < hnf.column
or hnf[1] == zerovec:
464 for j
in range(1, hnf.column + 1):
465 omega.append(list(hnf[j]))
470 scalar multiplication. 475 muled = [[c * scale
for c
in base]
for base
in self.
basis]
485 Return determinant of the basis (basis ought to be of full 486 rank and in Hermite normal form). 492 Return a list corresponding a linear combination of basis with 493 given coefficients. The denominator is ignored. 496 for c, base
in zip(coefficients, self.
basis):
498 new_basis[i] += c * base[i]