def sievesum1(n, p): """ Return the sum of all of the numbers not excluded by a sieve of [1..n] by all primes up to and including p. Uses the lucy_hedgehog algorithm for summing the primes in [0, n] (faster than a sieve) In theory this works. But for large n we hit maximum stack depth. And we are using prime() to check primality when we should be able to determine it from our own computation. """ if n == 0: retval = 0 elif p == 0: retval = n * (n + 1) // 2 - 1 elif (n, p) in sievesum_hash: return sievesum_hash[(n, p)] else: while not isprime(p): p -= 1 retval = sievesum(n, p - 1) if isprime(p) and p * p <= n: num_excluded = sievesum(n // p, p - 1) - sievesum(p - 1, p - 1) retval -= p * num_excluded sievesum_hash[(n, p)] = retval return retval
def biquadratic_residue_table(): print("""A table of biquadratic residues. Each column shows the values of the character associated with the prime at the top of the column """) maxp = 75 qprimes = [(flip(jacobi_sum_quartic(qq)) if (qq % 4 == 1) else GaussianInteger(qq)) for qq in range(3, maxp, 2) if isprime(qq)] pprimes = qprimes print('%5s' % ' ', end=' ') for pi2 in qprimes: print('%4s' % (GaussianInteger(pi2.real(), 0), ), end=' ') print('') print('%5s' % ' ', end=' ') for pi2 in qprimes: if pi2.imag() == 0: print('%4s' % ' ', end=' ') else: print('%+4s' % (GaussianInteger(0, pi2.imag()), ), end=' ') print('') for pi1 in pprimes: print('%5s' % (pi1, ), end=' ') for pi2 in qprimes: if pi1 == pi2: print('%4s' % ' ', end=' ') else: print('%4s' % (biquad(pi2, pi1), ), end=' ') print('')
def run(): print(u""" For the curve given by the affine equation x\u00B2 + y\u00B2 + x\u00B2y\u00B2 = 1 calculate the number of points on curve over the finite field Z/pZ. If p\u22611(4), and we write p=a\u00B2+b\u00B2 with a odd and b even and a\u22613(4) if b\u2261 2(4) a\u22611(4) if b\u2261 0(4) then Gauss conjectured that the number of points on this curve, including the 2 add'l points at infinity, should equal p-1-2a. Do a brute force calculation and verify this for such primes up to 199. """) for p in range(5, 200, 4): if isprime(p): ff = FiniteField(p, 1) f = gauss_polynomial(ff) np = count_curve_points_affine(f, ff) js = ff.jacobi_sum(4) a, b = normalize(js[0], js[1]) print('%4d %5d+2 = p-1%+3d, J=%+2.0f%+2.0fi' % (p, np, (np + 2 - p + 1), a, b))
def table2(): maxp = 75 q2primes = [ flip(jacobi_sum_quartic(qq)) for qq in range(5, maxp, 4) if isprime(qq) ] for pi1 in q2primes: for pi in [ pi1, GaussianInteger(pi1.real(), -pi1.imag()), GaussianInteger(-pi1.imag(), pi1.real()), GaussianInteger(-pi1.real(), -pi1.imag()), GaussianInteger(pi1.imag(), -pi1.real()), GaussianInteger(pi1.real(), -pi1.imag()), GaussianInteger(pi1.imag(), pi1.real()), GaussianInteger(-pi1.real(), pi1.imag()), GaussianInteger(-pi1.imag(), -pi1.real()) ]: chi = Character(pi) chi2 = chi * chi print('%10s %10s %10s %10s' % (pi, chi(GaussianInteger(-1)), jacobi_sum( chi, chi, pi.norm()), jacobi_sum(chi, chi2, pi.norm())))
def repsmod11(): p = 1 gen = genus(1, 0, 11) while True: if (p % 44) in gen and isprime(p): yield p, repmod11(p) p += 1
def legendre_ch(d): """ Return the mod abs(disc Q[√d]) Legendre character. This is the character ch with modulus D=abs(disc Q[√d]) such that for any odd prime p, ch(p)=(d/p) (i.e. ch(p)=0 if p|d ch(p)=1 if d is a square mod p ch(p)=-1 if d is not a square mod p """ if not squarefree(d): raise ValueError('%d is not square free' % (d, )) abs_disc = abs(discriminant(d)) vals = [0] * abs_disc for k in range(abs_disc): if gcd(abs_disc, k) == 1: n = k while True: if isprime(n) and n % 2 == 1: vals[k] = legendre(d, n) break n += abs_disc return lambda a: vals[a % abs_disc]
def run1(): """ Calculate the Jacobi sums of a cubic character for some finite fields of order p^2 """ zeta3 = np.cos(2*np.pi/3) + 1j*np.sin(2*np.pi/3) # These are all going to for p in (pp for pp in range(7, 200, 12) if isprime(pp)): nnp = p if (p % 4 == 1) else p*p # print 'Finite Field with %d^2=%d elements' % (p, p*p) def mul(a, b): # Here's how we multiply Gaussian integers return (a[0]*b[0]-a[1]*b[1]) % p, (a[0]*b[1]+a[1]*b[0]) % p def add(a, b): # Here's how we add Gaussian integers return ((a[0]+b[0]) % p), ((a[1]+b[1]) % p) def order(a): retval = 1 b = a while b != (1, 0): b = mul(b, a) retval += 1 return retval def prim_elt(): for x in range(p): for y in range(p): elt = (x, y) if elt == (0, 0): continue if order(elt) == p*p-1: return elt xx = prim_elt() powers = [(0, 0), (1, 0)] cnt = 0 while cnt < nnp-2: powers.append(mul(powers[-1], xx)) cnt += 1 chars = [0.0] + list(map(lambda n: zeta3**n, range(p*p))) avals = powers bvals = map(lambda yy: add((1, 0), mul((-1, 0), yy)), avals) bindices = [avals.index(bb) for bb in bvals] bchars = [chars[bi] for bi in bindices] jsum = sum(aa*bb for (aa, bb) in zip(chars, bchars)) # express jsum as an integral combination of 1 and zeta3=(-1+sqrt(3))/2 # c2 = jsum.imag/(np.sqrt(3.0)/2.0) tmp = jsum - c2*zeta3 c1 = tmp.real print('%6d %10d %35s %7.1f %7.1f %35s %s' % (p, p*p, jsum, c1, c2, c1+c2*zeta3, '%d+%di' % xx))
def primesum_naive(n): """ A slow, reference implementation. Add up the all of the primes in the range [0, n] """ retval = 0 k = 2 while k <= n: if isprime(k): retval += k k += 1 return retval
def run2(): for p in []: if not isprime(p): continue # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61] : cnt = 0 for x in range(p): for y in range(p): cnt += f(x, y, p) == 0 bound = 2*int(np.sqrt(p)) if abs(cnt-p) >= bound: print('%5d %5d %5d %5d' % (p, cnt, cnt - p, bound))
def test_isprime(self): self.assertEqual(False, isprime(0), 'zero is not a (maximal) prime') self.assertEqual(False, isprime(1), 'units are not prime') self.assertEqual(True, isprime(7), 'yes, 7 is a prime') self.assertEqual(False, isprime(49), 'a non-unit square is not prime') self.assertEqual(False, isprime(91), '91=7*13 is not prime') self.assertEqual(True, isprime(-7), '(some) negative numbers are prime') self.assertRaises(TypeError, isprime, 7.0)
def class_group_info(d): r""" :param d: a non-square integer :return: prints information relevant to the class group of the ring of integers in :math:`\mathbb{Q}(\sqrt{d})` """ mb = minkowski_bound(d) disc = discriminant(d) print('Discriminant = %d' % disc) print('Minkowski Bound = %d' % (mb, )) split_primes = [] for p in [pp for pp in range(2, mb + 1) if isprime(pp)]: fact = factorize_in(p, d) if fact == (p, ): print(fact) else: md = norm_search(p, d) print(fact, md) if md is None: split_primes.append(p) if (d % 4) != 1 and d > 0: print('approximant based elements and norms') print([(xx, xx.norm()) for xx in approximants(d)]) if not split_primes: print('No non principal primes under the Minkowski bound!') return print('Split primes') print(split_primes) print('Split primes that are not squares mod %d' % (d, )) sq = squares_mod_d(d) print( [pp for pp in split_primes if (pp not in sq) and ((d - pp) not in sq)]) for ii in range(len(split_primes)): for jj in range(ii, len(split_primes)): p = split_primes[ii] * split_primes[jj] md = norm_search(p, d) print(p, md) for ii in range(len(split_primes)): for jj in range(ii, len(split_primes)): for kk in range(jj, len(split_primes)): p = split_primes[ii] * split_primes[jj] * split_primes[kk] md = norm_search(p, d) print(p, md)
def all_modm_chars(m): r""" Returns a list of all mod m characters, starting with the trivial character. Only works with prime m for now. """ if not isprime(m): raise ValueError("%d is not a prime." % (m, )) a = primitive_root(m) zz = np.exp(2.0j * np.pi / (m - 1)) vals = [None] * (m - 1) pows = [0] + [modpow(a, k, m) for k in range(m - 1)] for k in range(m - 1): pows2 = [0] + [(zz**k)**i for i in range(m - 1)] vals[k] = dict(zip(pows, pows2)) return map(lambda val: (lambda ii: val[ii % m]), vals)
def run(): print(u""" For a fixed characteristic p (where 3 divides p-1), there is a unique (up to conjugation) non-trivial cubic character \u03C7 on F_{p^k}, and so the real part of the Jacobi sum J(\u03C7, \u03C7) only depends on the field F_{p^k}. Calculate J(\u03C7, \u03C7) for range of values of k to get an idea of how these values are related to each other. """) theta = 2*np.pi/3 zeta = np.cos(theta)+1j*np.sin(theta) pi = -1-3*zeta for p in [7, 13]: if isprime(p): for ii in range(1, 5): ff = FiniteField(p, ii) c0, c1 = ff.jacobi_sum(3) nk = count_diagonal_cubic_points(ff) print(u'%6d %+.0f%+.0f\u03c9 %4.0f %4d' % (p**ii, c0, c1, (p**ii+1)-(-1)**ii*(pi**ii + pi.conj()**ii).real, nk))
def legendre(a, p): """ Return (a/p), the Legendre symbol (p is prime) (a/p) = 0 if p|a = 1 if a is a quad residue mod p = -1 if a is a quad non-residue mod p """ a = a % p if a == 0: return 0 if a == 1: return 1 if a == -1: if p % 4 == 3: return -1 elif p % 4 == 1: return 1 else: return 0 if a == 2: p_mod_8 = p % 8 if p_mod_8 == 1 or p_mod_8 == 7: return 1 elif p_mod_8 == 3 or p_mod_8 == 5: return -1 else: return 0 if not isprime(a): return prod([legendre(q, p) for q, e in factorize2(a) if e % 2]) if p % 4 == 1 or a % 4 == 1: return legendre(p % a, a) else: return -legendre(p % a, a)