def crt(inlist): """ Chinese Remainder Theorem, Algo. 1.3.11 of Cohen's Book. """ k = len(inlist) if k < 2: raise ValueError("nothing to be done for one element") ccj = [None] # gabage to simplify loop index ellist = list(inlist) ellist.sort() modulus = 1 for j in range(1, k): modulus *= ellist[j - 1][1] d, tpl = gcd.gcd_of_list([modulus % ellist[j][1], ellist[j][1]]) if d > 1: raise ValueError("moduli are not pairwise coprime") ccj.append(tpl[0]) yj = [ellist[0][0] % ellist[0][1]] for j in range(1, k): ctp = yj[-1] for i in range(j - 2, -1, -1): ctp = yj[i] + ellist[i][1] * ctp yj.append(((ellist[j][0] - ctp) * ccj[j]) % ellist[j][1]) outp = yj.pop() for j in range(k - 2, -1, -1): outp = yj.pop() + (ellist[j][1]) * outp return outp
def class_number(disc, limit_of_disc=100000000): """ Return class number with the given discriminant by counting reduced forms. Not only fundamental discriminant. """ if disc & 3 not in (0, 1): raise ValueError("a discriminant must be 0 or 1 mod 4") if disc >= 0: raise ValueError("a discriminant must be negative") if -disc >= limit_of_disc: warnings.warn("the discriminant seems to have too big absolute value") h = 1 b = disc & 1 c_b = int(math.sqrt(-disc / 3)) while b <= c_b: q = (b**2 - disc) >> 2 a = b if a <= 1: a = 2 while a**2 <= q: if q % a == 0 and gcd.gcd_of_list([a, b, q // a])[0] == 1: if a == b or a**2 == q or b == 0: h += 1 else: h += 2 a += 1 b += 2 return h
def class_number(disc, limit_of_disc=100000000): """ Return class number with the given discriminant by counting reduced forms. Not only fundamental discriminant. """ if disc % 4 not in (0, 1): raise ValueError("a discriminant must be 0 or 1 mod 4") if disc >= 0: raise ValueError("a discriminant must be negative") if -disc >= limit_of_disc: warnings.warn("the discriminant seems to have too big absolute value") h = 1 b = disc % 2 c_b = int(math.sqrt(-disc / 3)) while b <= c_b: q = (b**2 - disc) // 4 a = b if a <= 1: a = 2 while a**2 <= q: if q % a == 0 and gcd.gcd_of_list([a, b, q//a])[0] == 1: if a == b or a**2 == q or b == 0: h += 1 else: h += 2 a += 1 b += 2 return h
def compositePDF(f_1, f_2): """ Return the reduced form of composition of the given forms 'f_1' and 'f_2'. 'f_1' and 'f_2' are quadratic forms with same disc. """ if gcd.gcd_of_list(f_1)[0] != 1: raise ValueError( "coefficients of a quadratic form must be relatively prime") if gcd.gcd_of_list(f_2)[0] != 1: raise ValueError( "coefficients of a quadratic form must be relatively prime") if disc(f_1) != disc(f_2): raise ValueError("two quadratic forms must have same discriminant") if f_1[0] > f_2[0]: f_1, f_2 = f_2, f_1 s = (f_1[1] + f_2[1]) >> 1 n = f_2[1] - s if f_2[0] % f_1[0] == 0: y_1 = 0 d = f_1[0] else: u, v, d = euclid_exd(f_2[0], f_1[0]) y_1 = u if s % d == 0: y_2 = -1 x_2 = 0 d_1 = d else: u, v, d_1 = euclid_exd(s, d) x_2 = u y_2 = -v v_1 = f_1[0] // d_1 v_2 = f_2[0] // d_1 r = (y_1 * y_2 * n - x_2 * f_2[2]) % v_1 b_3 = f_2[1] + 2 * v_2 * r a_3 = v_1 * v_2 c_3 = (f_2[2] * d_1 + r * (f_2[1] + v_2 * r)) // v_1 return reducePDF((a_3, b_3, c_3))
def compositePDF(f_1, f_2): """ Return the reduced form of composition of the given forms 'f_1' and 'f_2'. 'f_1' and 'f_2' are quadratic forms with same disc. """ if gcd.gcd_of_list(f_1)[0] != 1: raise ValueError("coefficients of a quadratic form must be relatively prime") if gcd.gcd_of_list(f_2)[0] != 1: raise ValueError("coefficients of a quadratic form must be relatively prime") if disc(f_1) != disc(f_2): raise ValueError("two quadratic forms must have same discriminant") if f_1[0] > f_2[0]: f_1, f_2 = f_2, f_1 s = (f_1[1] + f_2[1]) // 2 n = f_2[1] - s if f_2[0] % f_1[0] == 0: y_1 = 0 d = f_1[0] else: u, v, d = euclid_exd(f_2[0], f_1[0]) y_1 = u if s % d == 0: y_2 = -1 x_2 = 0 d_1 = d else: u, v, d_1 = euclid_exd(s, d) x_2 = u y_2 = -v v_1 = f_1[0] // d_1 v_2 = f_2[0] // d_1 r = (y_1*y_2*n - x_2*f_2[2]) % v_1 b_3 = f_2[1] + 2*v_2*r a_3 = v_1*v_2 c_3 = (f_2[2]*d_1 + r*(f_2[1] + v_2*r)) // v_1 return reducePDF((a_3, b_3, c_3))
def class_group(disc, limit_of_disc=100000000): """ Return the class number and the class group with the given discriminant by counting reduced forms. Not only fundamental discriminant. """ if disc % 4 not in (0, 1): raise ValueError("a discriminant must be 0 or 1 mod 4") if disc >= 0: raise ValueError("a discriminant must be negative") if -disc >= limit_of_disc: warnings.warn("the discriminant seems to have too big absolute value") h = 1 b = disc % 2 c_b = int(math.sqrt(-disc / 3)) ret_list = [] f_a = 1 if disc % 4 == 0: f_b = 0 f_c = -(disc // 4) else: f_b = 1 f_c = -((disc - 1) // 4) unit = (f_a, f_b, f_c) ret_list.append(ReducedQuadraticForm(unit, unit)) while b <= c_b: q = (b**2 - disc) // 4 a = b if a <= 1: a = 2 while a**2 <= q: if q % a == 0 and gcd.gcd_of_list([a, b, q//a])[0] == 1: f_c = (b**2 - disc) // (4 * a) if a == b or a**2 == q or b == 0: h += 1 ret_list.append(ReducedQuadraticForm((a, b, f_c), unit)) else: h += 2 ret_list.append(ReducedQuadraticForm((a, b, f_c), unit)) ret_list.append(ReducedQuadraticForm((a, -b, f_c), unit)) a += 1 b += 2 return h, ret_list
def class_group(disc, limit_of_disc=100000000): """ Return the class number and the class group with the given discriminant by counting reduced forms. Not only fundamental discriminant. """ if disc & 3 not in (0, 1): raise ValueError("a discriminant must be 0 or 1 mod 4") if disc >= 0: raise ValueError("a discriminant must be negative") if -disc >= limit_of_disc: warnings.warn("the discriminant seems to have too big absolute value") h = 1 b = disc & 1 c_b = int(math.sqrt(-disc / 3)) ret_list = [] f_a = 1 if disc & 3 == 0: f_b = 0 f_c = -(disc >> 2) else: f_b = 1 f_c = -((disc - 1) >> 2) unit = (f_a, f_b, f_c) ret_list.append(ReducedQuadraticForm(unit, unit)) while b <= c_b: q = (b**2 - disc) >> 2 a = b if a <= 1: a = 2 while a**2 <= q: if q % a == 0 and gcd.gcd_of_list([a, b, q // a])[0] == 1: f_c = (b**2 - disc) // (4 * a) if a == b or a**2 == q or b == 0: h += 1 ret_list.append(ReducedQuadraticForm((a, b, f_c), unit)) else: h += 2 ret_list.append(ReducedQuadraticForm((a, b, f_c), unit)) ret_list.append(ReducedQuadraticForm((a, -b, f_c), unit)) a += 1 b += 2 return h, ret_list
def __init__(self, valuelist, polynomial, precompute=False): if len(polynomial) != len(valuelist[0])+1: raise ValueError self.value = valuelist self.coeff = valuelist[0] self.denom = valuelist[1] self.degree = len(polynomial) - 1 self.polynomial = polynomial self.field = NumberField(self.polynomial) Gcd = gcd.gcd_of_list(self.coeff) GCD = gcd.gcd(Gcd[0], self.denom) if GCD != 1: self.coeff = [i//GCD for i in self.coeff] self.denom = self.denom//GCD if precompute: self.getConj() self.getApprox() self.getCharPoly()
def __init__(self, valuelist, polynomial, precompute=False): if len(polynomial) != len(valuelist[0]) + 1: raise ValueError self.value = valuelist self.coeff = valuelist[0] self.denom = valuelist[1] self.degree = len(polynomial) - 1 self.polynomial = polynomial self.field = NumberField(self.polynomial) Gcd = gcd.gcd_of_list(self.coeff) GCD = gcd.gcd(Gcd[0], self.denom) if GCD != 1: self.coeff = [i // GCD for i in self.coeff] self.denom = self.denom // GCD if precompute: self.getConj() self.getApprox() self.getCharPoly()
def randomele(disc, unit): """ Return a reduced random form with the given discriminant and the given unit. Also random element is not unit. """ limit = int(math.sqrt(-disc / 3)) while True: a = bigrandom.randrange(1, limit + 1) ind = 0 while ind < 2*a: b = bigrandom.randrange(a) if bigrandom.randrange(2): b = -b tp = disc - b**2 if tp % (-4 * a) == 0: c = tp // (-4 * a) if gcd.gcd_of_list([a, b, c])[0] != 1: continue red = reducePDF((a, b, c)) if red != unit: return ReducedQuadraticForm(red, unit) ind += 1
def randomele(disc, unit): """ Return a reduced random form with the given discriminant and the given unit. Also random element is not unit. """ limit = int(math.sqrt(-disc / 3)) while True: a = bigrandom.randrange(1, limit + 1) ind = 0 while ind < 2 * a: b = bigrandom.randrange(a) if bigrandom.randrange(2): b = -b tp = disc - b**2 if tp % (-4 * a) == 0: c = tp // (-4 * a) if gcd.gcd_of_list([a, b, c])[0] != 1: continue red = reducePDF((a, b, c)) if red != unit: return ReducedQuadraticForm(red, unit) ind += 1
def testGcdOfList(self): self.assertEqual([8, [1]], gcd.gcd_of_list([8])) self.assertEqual([1, [-4, 3]], gcd.gcd_of_list([8, 11])) self.assertEqual([1, [-4, 3, 0, 0, 0, 0, 0]], gcd.gcd_of_list([8, 11, 10, 9, 6, 5, 4]))