#!/usr/bin/env python
# Author: Jared Brothers
#
# A Python version of the Haskell code from
# "The Genuine Sieve of Eratosthenes"
# www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf
#
import heapq, itertools, operator
def sieve(xs):
"""Generate the prime numbers, given an iterable of candidate numbers.
Cross off multiples of prime numbers incrementally using iterators."""
table = []
while 1:
x = xs.next()
if table == [] or x < table[0][0]:
yield x
xs, ys = itertools.tee(xs)
timesx = (lambda x: lambda y: x*y)(x)
heapq.heappush(table, (x**2, itertools.imap(timesx, ys)))
else:
while table[0][0] <= x:
heapq.heapreplace(table, (table[0][1].next(), table[0][1]))
def wheel(factors=[2, 3, 5, 7], next=11):
"""Generate the distances between numbers not divisible by a list of small
primes, from the next prime up to the product of the list."""
circumference = reduce(operator.mul, factors)
prev = next
next += 1
end = next + circumference
while next < end:
if not any(next % factor == 0 for factor in factors):
yield next - prev
prev = next
next += 1
def spin(factors=[2, 3, 5, 7], next=11):
"""Generate candidates by making a wheel and cycling through it."""
for gap in itertools.cycle(wheel(factors, next)):
yield next
next += gap
def primes(k=5):
"""Generate primes with the sieve and wheel factorization, which filters
multiples of the first k primes."""
smallprimes = list(itertools.islice(sieve(itertools.count(2)), k + 1))
factors = smallprimes[:-1]
next = smallprimes[-1]
return itertools.chain(factors, sieve(spin(factors, next)))
Labels: haskell, lazy, papers, python
November 2008 December 2008 January 2009 June 2009 July 2009
Subscribe to Posts [Atom]
Post a Comment