def isfinished_bsgscv(n, sossp, sogsp, nt, lpt, qpt, disc, classnum, indofg): """ Determine whether the bsgs algorithm is finished or not yet. This is a submodule called by the bsgs module. """ lpt.append(n) sumn = 1 for nid in lpt: sumn = sumn * nid if sumn == qpt: return True, sossp, sogsp elif sumn > qpt: raise ValueError if n == 1: return False, sossp, sogsp else: tpsq = misc.primePowerTest(n) if (tpsq[1] != 0) and ((tpsq[1] % 2) == 0): q = arith1.floorsqrt(n) else: q = arith1.floorsqrt(n) + 1 ss = sossp.retel() new_sossp = ClassGroup(disc, classnum, []) tnt = copy.deepcopy(nt) for i in range(q): base = tnt ** i for ssi in ss: newel = base * ssi if new_sossp.search(newel) is False: newel.alpha = ssi.alpha[:] lenal = len(newel.alpha) sfind = indofg - lenal for sit in range(sfind): newel.alpha.append([lenal + sit, 0, 0]) newel.alpha.append([indofg, tnt, i]) new_sossp.insttree(newel) # multiple of two elements of G y = nt ** q ltl = sogsp.retel() new_sogsp = ClassGroup(disc, classnum, []) for i in range(q + 1): base = y ** (-i) for eol in ltl: newel2 = base * eol if new_sogsp.search(newel2) is False: newel2.beta = eol.beta[:] lenbt = len(newel2.beta) gfind = indofg - lenbt for git in range(gfind): newel2.beta.append([lenbt + git, 0, 0]) newel2.beta.append([indofg, tnt, q * (-i)]) new_sogsp.insttree(newel2) # multiple of two elements of G return False, new_sossp, new_sogsp
def isfinished_bsgscv(n, sossp, sogsp, nt, lpt, qpt, disc, classnum, indofg): """ Determine whether the bsgs algorithm is finished or not yet. This is a submodule called by the bsgs module. """ lpt.append(n) sumn = 1 for nid in lpt: sumn = sumn * nid if sumn == qpt: return True, sossp, sogsp elif sumn > qpt: raise ValueError if n == 1: return False, sossp, sogsp else: tpsq = misc.primePowerTest(n) if (tpsq[1] != 0) and ((tpsq[1] & 1) == 0): q = arith1.floorsqrt(n) else: q = arith1.floorsqrt(n) + 1 ss = sossp.retel() new_sossp = ClassGroup(disc, classnum, []) tnt = copy.deepcopy(nt) for i in range(q): base = tnt**i for ssi in ss: newel = base * ssi if new_sossp.search(newel) is False: newel.alpha = ssi.alpha[:] lenal = len(newel.alpha) sfind = indofg - lenal for sit in range(sfind): newel.alpha.append([lenal + sit, 0, 0]) newel.alpha.append([indofg, tnt, i]) new_sossp.insttree(newel) # multiple of two elements of G y = nt**q ltl = sogsp.retel() new_sogsp = ClassGroup(disc, classnum, []) for i in range(q + 1): base = y**(-i) for eol in ltl: newel2 = base * eol if new_sogsp.search(newel2) is False: newel2.beta = eol.beta[:] lenbt = len(newel2.beta) gfind = indofg - lenbt for git in range(gfind): newel2.beta.append([lenbt + git, 0, 0]) newel2.beta.append([indofg, tnt, q * (-i)]) new_sogsp.insttree(newel2) # multiple of two elements of G return False, new_sossp, new_sogsp
def class_number_bsgs(disc): """ Return the class number with the given 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") lx = max(arith1.floorpowerroot(abs(disc), 5), 500 * (math.log(abs(disc)))**2) uprbd = int(class_formula(disc, int(lx)) * 3 / 2) lwrbd = (uprbd >> 1) + 1 bounds = [lwrbd, uprbd] # get the unit element = RetNext(disc) ut = element.unit() # append the unit to subset of G sossp = ClassGroup(disc, 0, []) sogsp = ClassGroup(disc, 0, []) sossp.insttree(ut) sogsp.insttree(ut) h = 1 # order finished = False while not finished: mstp1 = bounds[1] - bounds[0] if mstp1 <= 1: q = 1 else: q = arith1.floorsqrt(mstp1) if misc.primePowerTest(mstp1)[1] != 2: q += 1 # get next element nt = element.retnext() # x is the set of elements of G x = [ut, nt**h] if q > 2: x.extend([0] * (q - 2)) # compute small steps if x[1] == ut: # compute the order of nt n = trorder(h, sossp, sogsp, nt, disc) else: n = trbabysp(q, x, bounds, sossp, sogsp, ut, h, nt, disc) # finished? finished, h, sossp, sogsp = isfinished_trbsgs(lwrbd, bounds, h, n, sossp, sogsp, nt, disc) return h
def class_number_bsgs(disc): """ Return the class number with the given 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") lx = max(arith1.floorpowerroot(abs(disc), 5), 500 * (math.log(abs(disc)))**2) uprbd = int(class_formula(disc, int(lx)) * 3 / 2) lwrbd = uprbd // 2 + 1 bounds = [lwrbd, uprbd] # get the unit element = RetNext(disc) ut = element.unit() # append the unit to subset of G sossp = ClassGroup(disc, 0, []) sogsp = ClassGroup(disc, 0, []) sossp.insttree(ut) sogsp.insttree(ut) h = 1 # order finished = False while not finished: mstp1 = bounds[1] - bounds[0] if mstp1 <= 1: q = 1 else: q = arith1.floorsqrt(mstp1) if misc.primePowerTest(mstp1)[1] != 2: q += 1 # get next element nt = element.retnext() # x is the set of elements of G x = [ut, nt ** h] if q > 2: x.extend([0] * (q - 2)) # compute small steps if x[1] == ut: # compute the order of nt n = trorder(h, sossp, sogsp, nt, disc) else: n = trbabysp(q, x, bounds, sossp, sogsp, ut, h, nt, disc) # finished? finished, h, sossp, sogsp = isfinished_trbsgs(lwrbd, bounds, h, n, sossp, sogsp, nt, disc) return h
def testPrimePowerTest(self): # not a power self.assertEqual((12, 0), misc.primePowerTest(12)) self.assertEqual((53, 1), misc.primePowerTest(53)) # not a prime power self.assertEqual((36, 0), misc.primePowerTest(36)) # powers self.assertEqual((7, 2), misc.primePowerTest(49)) self.assertEqual((3, 4), misc.primePowerTest(81)) self.assertEqual((5, 3), misc.primePowerTest(125)) self.assertEqual((2, 7), misc.primePowerTest(128))
def babyspcv(bounds, sossp, sogsp, utwi, nt, disc, classnum): """ Compute small steps """ mstp1 = bounds[1] - bounds[0] if (mstp1 == 0) or (mstp1 == 1): q = 1 else: tppm = misc.primePowerTest(mstp1) q = arith1.floorsqrt(mstp1) if (tppm[1] == 0) or (tppm[1] % 2): q += 1 n_should_be_set = True # initialize c_s1 = ClassGroup(disc, classnum, []) # a subset of G # extracting i = 0 case of main loop for ttr in sossp.retel(): tmpx = ttr tmpx.s_parent = ttr # tmpx belongs ttr in the set of smallstep # index of the element tmpx.ind = 0 c_s1.insttree(tmpx) # main loop x_i = nt for i in range(1, q): for ttr in sossp.retel(): tmpx = x_i * ttr tmpx.s_parent = ttr # tmpx belongs ttr in the set of smallstep if n_should_be_set and tmpx == utwi: n = i tmp_ss = tmpx.s_parent tmp_gs = utwi n_should_be_set = False # index of the element tmpx.ind = i c_s1.insttree(tmpx) x_i = nt * x_i assert x_i == nt ** q if n_should_be_set: sz = nt ** bounds[0] n, tmp_ss, tmp_gs = giantspcv(q, sz, x_i, c_s1, bounds, sogsp) return ordercv(n, sossp, sogsp, nt, disc, classnum, tmp_ss, tmp_gs)
def generate(self, target, **options): """ Generate squarefree factors of the target number with their valuations. The method may terminate with yielding (1, 1) to indicate the factorization is incomplete. If a keyword option 'strict' is False (default to True), factorization will stop after the first square factor no matter whether it is squarefree or not. """ strict = options.get('strict', True) options['n'] = target primeseq = self._parse_seq(options) for p in primeseq: if not (target % p): e, target = arith1.vp(target, p) yield p, e if target == 1: break elif e > 1 and not strict: yield 1, 1 break elif trivial_test_ternary(target): # the factor remained is squarefree. yield target, 1 break q, e = factor_misc.primePowerTest(target) if e: yield q, e break sqrt = arith1.issquare(target) if sqrt: if strict: for q, e in self.factor(sqrt, iterator=primeseq): yield q, 2 * e else: yield sqrt, 2 break if p ** 3 > target: # there are no more square factors of target, # thus target is squarefree yield target, 1 break else: # primeseq is exhausted but target has not been proven prime yield 1, 1
def babyspcv(bounds, sossp, sogsp, utwi, nt, disc, classnum): """ Compute small steps """ mstp1 = bounds[1] - bounds[0] if (mstp1 == 0) or (mstp1 == 1): q = 1 else: tppm = misc.primePowerTest(mstp1) q = arith1.floorsqrt(mstp1) if (tppm[1] == 0) or (tppm[1] & 1): q += 1 n_should_be_set = True # initialize c_s1 = ClassGroup(disc, classnum, []) # a subset of G # extracting i = 0 case of main loop for ttr in sossp.retel(): tmpx = ttr tmpx.s_parent = ttr # tmpx belongs ttr in the set of smallstep # index of the element tmpx.ind = 0 c_s1.insttree(tmpx) # main loop x_i = nt for i in range(1, q): for ttr in sossp.retel(): tmpx = x_i * ttr tmpx.s_parent = ttr # tmpx belongs ttr in the set of smallstep if n_should_be_set and tmpx == utwi: n = i tmp_ss = tmpx.s_parent tmp_gs = utwi n_should_be_set = False # index of the element tmpx.ind = i c_s1.insttree(tmpx) x_i = nt * x_i assert x_i == nt**q if n_should_be_set: sz = nt**bounds[0] n, tmp_ss, tmp_gs = giantspcv(q, sz, x_i, c_s1, bounds, sogsp) return ordercv(n, sossp, sogsp, nt, disc, classnum, tmp_ss, tmp_gs)
def isfinished_trbsgs(lwrbd, bounds, h, n, sossp, sogsp, nt, disc): """ Determine whether bsgs is finished or not yet. This is a submodule called by the bsgs module. lwrbd, h, n: int nt: element """ h *= n if h >= lwrbd: result = True elif n == 1: result = False else: bounds[0] = (bounds[0] + n - 1) // n # ceil of lower bound // n bounds[1] = bounds[1] // n # floor of upper bound // n q = arith1.floorsqrt(n) if misc.primePowerTest(n)[1] != 2: q = arith1.floorsqrt(n) + 1 # ceil of sqrt sossp, sogsp = _update_subgrps(q, nt, sossp, sogsp, disc) result = False return result, h, sossp, sogsp