Python's faster alternative to lists for prime numbers? - python-2.7

I need to find the first pair of primes within specified range, these primes must be a certain difference from each other and have no other primes within that difference.
My code seems to be working, but it is painfully slow - I presume because of my use of lists to handle primes. What would be a better approach?
g=difference;
n=first number in range
m= second number in range
def gap(g,n,m):
prime_list = []
for num in range(n,m+1):
if all(num%i!=0 for i in range(2,int(num**0.5)+1)):
prime_list.append(num)
if len(prime_list)<1:
return None
for pnum in prime_list:
for index in range(len(prime_list)):
pnum2 = prime_list[index]
diff = abs(pnum - pnum2)
if diff == g:
checker = abs(prime_list.index(pnum2) - prime_list.index(pnum))
if checker <=1:
return [pnum, pnum2]
Some tests:
Test.assert_equals(gap(2,100,110), [101, 103])
Test.assert_equals(gap(4,100,110), [103, 107])
Test.assert_equals(gap(2, 10000000, 11000000), [10000139, 10000141])

Why store the primes in a list at all? You only need to remember one at a time. You'll be working through them in ascending order and, as jasonharper points out, all you need to do is stop when you encounter the first delta equal to g between successive primes:
def gap(g, n, m):
previous_prime = None
for candidate in range(n, m + 1):
if all(candidate % factor for factor in range(2, int(candidate ** 0.5) + 1)):
if previous_prime is not None and candidate - previous_prime == g:
return [previous_prime, candidate]
previous_prime = candidate

Related

Product of three primes divisible by sum of those primes

I found this problem in a cp contest which is over now so it can be answered.
Three primes (p1,p2,p3) (not necessarily distinct) are called special if (p1+p2+p3) divides p1*p2*p3. We have to find the number of these special pairs if the primes can't exceed 10^6
I tried brute force method but it timed out. Can there be any other method?
If you are timing out, then you need to do some smart searching to replace brute force. There are just short of 80,000 primes below a million so it is not surprising you timed out.
So, you need to start looking more carefully.
For example, any triple (2, p, p+2) where p+2 is also prime will meet the criteria:
2 + 3 + 5 = 10; 2 * 3 * 5 = 30; 30 / 10 = 3.
2 + 5 + 7 = 14; 2 * 5 * 7 = 70. 70 / 14 = 5.
...
2 + p + p+2 = 2(p+2); 2 * p * (p+2) = 2p(p+2); 2p(p+2) / 2(p+2) = p.
...
Are there other triples that start with 2? Are there triples that start with 3? What forms do p2 and p3 take if p1= 3? Run your program for triples up to 500 or so and look for patterns in the results. Then extrapolate those results to 10^6.
I assume you are using a Sieve to generate your initial list of primes.
I've experimented with this problem since you posted it. I've not solved it, but wanted to pass along what insight I have before I move onto something else:
Generating Primes is Not the Issue
With a proper sieve algorithm, we can generate all primes under 10**6 in a fraction of a second. (Less than 1/3 of a second on my Mac mini.) Spending time optimizing prime generation beyond this is time wasted.
The Brute Force Method
If we try to generate all permutations of three primes in Python, e.g.:
for prime_1 in primes:
for prime_2 in primes:
if prime_2 < prime_1:
continue
for prime_3 in primes:
if prime_3 < prime_2:
continue
pass
Or better yet, push the problem down to the C level via Python's itertools:
from itertools import combinations_with_replacement
for prime_1, prime_2, prime_3 in combinations_with_replacement(primes, 3):
pass
Then, our timings, doing no actual work except generating prime triples, looks like:
sec.
10**2 0.04
10**3 0.13
10**4 37.37
10**5 ?
You can see how much time increases with each order of magnitude. Here's my example of a brute force solution:
from itertools import combinations_with_replacement
def sieve_primes(n): # assumes n > 1
sieve = [False, False, True] + [True, False] * ((n - 1) // 2)
p = 3
while p * p <= n:
if sieve[p]:
for i in range(p * p, n + 1, p):
sieve[i] = False
p += 2
return [number for number, isPrime in enumerate(sieve) if isPrime]
primes = sieve_primes(10 ** 3)
print("Finished Sieve:", len(primes), "primes")
special = 0
for prime_1, prime_2, prime_3 in combinations_with_replacement(primes, 3):
if (prime_1 * prime_2 * prime_3) % (prime_1 + prime_2 + prime_3) == 0:
special += 1
print(special)
Avoid Generating Triples, but Still Brute Force
Here's an approach that avoids generating triples. We take the smallest and largest primes we generated, cube them, and loop over them with a custom factoring function. This custom factoring function only returns a value for those numbers that are made up of exactly three prime factors. For any number made up of more or less, it returns None. This should be faster than normal factoring as the function can give up early.
Numbers that factor into exactly three primes are easy to test for specialness. We're going to pretend our custom factoring function takes no time at all and simply measure how long it takes us to loop over all the numbers in question:
smallest_factor, largest_factor = primes[0], primes[-1]
for number in range(smallest_factor**3, largest_factor**3):
pass
Again, some timings:
sec.
10**2 0.14
10**3 122.39
10**4 ?
Doesn't look promising. In fact, worse than our original brute force method. And our custom factoring function in reality adds a lot of time. Here's my example of this solution (copy sieve_primes() from the previous example):
def factor_number(n, count):
size = 0
factors = []
for prime in primes:
while size < count and n % prime == 0:
factors.append(prime)
n //= prime
size += 1
if n == 1 or size == count:
break
if n > 1 or size < count:
return None
return factors
primes = sieve_primes(10 ** 3)
print("Finished Sieve:", len(primes), "primes")
special = 0
smallest_factor, largest_factor = primes[0], primes[-1]
for number in range(smallest_factor**3, largest_factor**3):
factors = factor_number(number, 3)
if factors:
if number % sum(factors) == 0:
special += 1
print(special)

Automatically created list from printed objects

I'm new to Python and am learning via edX and trying to solve ProjectEuler math problems. The second problem is about summing all even Fibonacci numbers that are less than 4,000,000. I was able to solve this problem with Python, but not in a way that was satisfying to me.
First I defined a fib function:
def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
Then, I was able to print all even Fibonacci numbers with value less than 4,000,000:
n = 0
while True:
if fib(n) < 40000000 and fib(n) % 2 == 0:
print(fib(n))
n = n+1
elif fib(n) < 4000000 and fib(n) % 2 != 0:
n = n+1
else:
break
Then, I manually formed a list from what was printed and summed the list. The problem is that I don't want to have to do that. I want the computer to form the list as it goes and then sums up the value. Anyone know how I can do that? Thanks!
You could write a generator that produces fib numbers, then just take from it while the numbers are less than 4 million (4e6):
import itertools
def fib(n):
if n == 0: return 0
elif n == 1: return 1
else: return fib(n-1) + fib(n-2)
# A generator function that lazily produces new fib numbers
def gen_fibs():
n = 1
while True:
yield fib(n)
n += 1
# Take from the generator while n is less than 4 million
fibs = itertools.takewhile(lambda n: n <= 4e6, gen_fibs())
# Keep all the evens
even_fibs = (n for n in fibs if n % 2 == 0)
# Then print the sum of even fibs
print(sum(even_fibs))
There may be a way to get around defining the generator manually, but this is still fairly neat. If range had a 0-arity version that produced an infinite list, I could have reduced the first part down to a generator expression instead, but such is life.

Find minimum prime numbers which sum to a given value

I want to find the minimum set of prime numbers which would sum to a given value e.g. 9 = 7 + 2 (not 3+3+3).
I have already generated a array of prime numbers using sieve of eratosthens
I am traversing the array in descending order to get the array largest prime number smaller than or equal to given number. This works great if the number is odd.
But fails for even numbers e.g 122 = 113 + 7 + 2 but 122 = 109 +13.
From Golbach's Conjecture we know that any even number can be represented as two sum of two prime numbers. So if a number is even we can directly return 2 as output.
But I am trying to figure out a way other than brute force to find minimum prime numbers.
Although your question didn't say so, I assume you are looking for the set of primes that has the smallest cardinality.
If n is even, then consider the primes p in order, 2, 3, 5, …; eventually n - p will be prime, so n is the sum of two primes. This process typically converges very quickly, with the smaller of the two primes seldom larger than 1000 (and usually much smaller than that).
If n is odd, and n - 2 is prime, then n is the sum of the primes 2 and n - 2.
If n is odd, and n - 2 is not prime, then n - 3 is even and can be written as the sum of two primes, as described above.
Thus you can always find two or three primes that sum to any target n greater than 3.
Try this out!
Not an ideal code but if you want to have a working solution :P
primes = [2,3,5,7]
D = 29
i = -1
sum_ = 0
count = 0
while sum_ != D :
sum_ = sum_ + primes[i]
count += 1
if (sum_ == D) :
break
elif D - sum_ == primes[i-1] :
count += 1
break
elif D - sum_ < ex[i-1] and (D-sum_ not in primes) :
sum_ = sum_ - primes[i]
count = count - 1
i = i - 1
print(count)

Subset sum variant with a non-zero target sum

I have an array of integers and need to apply a variant of the subset sum algorithm on it, except that instead of finding a set of integers whose sum is 0 I am trying to find a set of integers whose sum is n. I am unclear as to how to adapt one of the standard subset sum algorithms to this variant and was hoping for any insight into the problem.
This is subset sum problem, which is NP-Complete (there is no known efficient solution to NP-Complete problems), but if your numbers are relatively small integers - there is an efficient pseudo polynomial solution to it that follows the recurrence:
D(x,i) = false x<0
D(0,i) = true
D(x,0) = false x != 0
D(x,i) = D(x,i-1) OR D(x-arr[i],i-1)
Later, you need to step back on your choices, see where you decided to "reduce" (take the element), and where you decided not to "reduce" (not take the element), on the generated matrix.
This thread and this thread discuss how to get the elements for similar problems.
Here is a python code (taken from the thread I linked to) that does the trick.
If you are not familiar with python - read it as pseudo code, it's pretty easy to understand python!.
arr = [1,2,4,5]
n = len(arr)
SUM = 6
#pre processing:
D = [[True] * (n+1)]
for x in range(1,SUM+1):
D.append([False]*(n+1))
#DP solution to populate D:
for x in range(1,SUM+1):
for i in range(1,n+1):
D[x][i] = D[x][i-1]
if x >= arr[i-1]:
D[x][i] = D[x][i] or D[x-arr[i-1]][i-1]
print D
#get a random solution:
if D[SUM][n] == False:
print 'no solution'
else:
sol = []
x = SUM
i = n
while x != 0:
possibleVals = []
if D[x][i-1] == True:
possibleVals.append(x)
if x >= arr[i-1] and D[x-arr[i-1]][i-1] == True:
possibleVals.append(x-arr[i-1])
#by here possibleVals contains 1/2 solutions, depending on how many choices we have.
#chose randomly one of them
from random import randint
r = possibleVals[randint(0,len(possibleVals)-1)]
#if decided to add element:
if r != x:
sol.append(x-r)
#modify i and x accordingly
x = r
i = i-1
print sol
You can solve this by using dynamic programming.
Lets assume that:
N - is the sum that required (your first input).
M - is the number of summands available (your second input).
a1...aM - are the summands available.
f[x] is true when you can reach the sum of x, and false otherwise
Now the solution:
Initially f[0] = true and f[1..N] = false - we can reach only the sum of zero without taking any summand.
Now you can iterate over all ai, where i in [1..M], and with each of them perform next operation:
f[x + ai] = f[x + ai] || f[x], for each x in [M..ai] - the order of processing is relevant!
Finally you output f[N].
This solution has the complexity of O(N*M), so it is not very useful when you either have large input numbers or large number of summands.

Exponential form of prime factorization in python

I have to Convert positive integer number into its prime factorization form exponentially. For example:[(2,1), (5,1)] is the correct prime factorization of 10 as defined above.
I have this below code to generate factors.Now I should make them prime and should return their exponents also in tuples . Pl help me.
def primes(n):
divisors = [ d for d in range(2,n//2+1) if n % d == 0]
return divisors
You can directly follow the following approach which is O(n^(1/2)) in time complexity.
# n is the number to be factorized
# this list holds your desired answer
prime_factors = []
# this variable iterates over prime
start = 2
while start*start <= n:
if n % start == 0:
expo = 0
while n % start == 0:
expo = expo + 1
n = n / start
prime_factors.append([start,expo])
if n > 1:
prime_factors.append([n,1])
print prime_factors
This is a simple iterative method. Here is running version Prime Factorization. Click on right upper corner ( fork ) to run on your test case
n = 10. Can run on others also.