Primes with runs

Problem 111

Considering 4-digit primes containing repeated digits it is clear that they cannot all be the same: 1111 is divisible by 11, 2222 is divisible by 22, and so on. But there are nine 4-digit primes containing three ones:
1117, 1151, 1171, 1181, 1511, 1811, 2111, 4111, 8111
We shall say that M(n, d) represents the maximum number of repeated digits for an n-digit prime where d is the repeated digit, N(n, d) represents the number of such primes, and S(n, d) represents the sum of these primes.
So M(4, 1) = 3 is the maximum number of repeated digits for a 4-digit prime where one is the repeated digit, there are N(4, 1) = 9 such primes, and the sum of these primes is S(4, 1) = 22275. It turns out that for d = 0, it is only possible to have M(4, 0) = 2 repeated digits, but there are N(4, 0) = 13 such cases.
In the same way we obtain the following results for 4-digit primes.
Digit, dM(4, d)N(4, d)S(4, d)
021367061
13922275
2312221
331246214
4328888
5315557
6316661
73957863
8318887
93748073
For d = 0 to 9, the sum of all S(4, d) is 273700.
Find the sum of all S(10, d).
from tools import is_probable_prime

number = [0] * 10

def check_number():
    if number[0] == 0:
        return 0

    n = 0
    for i in range(len(number)):
        n = n * 10 + number[i]

    if is_probable_prime(n, [2, 3, 5, 7, 11]):
        return n

    return 0

def recurse(base_digit, start_pos, level, fill=False):
    if level <= 0:
        return check_number()

    result = 0
    if fill:
        for pos in range(len(number)):
            number[pos] = base_digit

    for pos in range(start_pos, len(number)):
        for val in range(10):
            number[pos] = val
            result += recurse(base_digit, pos + 1, level - 1)
            number[pos] = base_digit

    return result

def run():
    result = 0
    for d in range(10):
        for i in range(1, len(number)):
            total = recurse(d, 0, i, True)
            if total > 0:
                result += total
                break

    return result

if __name__ == '__main__':
    run()














# PERMUTATIONS WITHOUT REPETITION
# Luka Rahne @ http://stackoverflow.com/questions/6284396/permutations-with-unique-values/6285203#6285203
# (modified)
def permutations_wor(elements):  # permutations without repetitions
    def recurse(listunique, p_list, d):
        if d < 0:
            yield tuple(p_list)
        else:
            for i in [j for j in listunique if j[1] > 0]:
                p_list[d] = i[0]
                i[1] -= 1
                for g in recurse(listunique, p_list, d - 1):
                    yield g
                i[1] += 1

    listunique = [[i, elements.count(i)] for i in set(elements)]
    l = len(elements)
    return recurse(listunique, [0] * l, l - 1)


# Primality test function based on Fermat/Euler pseudoprime test.
# To be used for large numbers (>1e6)
def isprimeFE(n):  # http://www.math.umbc.edu/~campbell/Computers/Python/numbthy.py
    """
    isprimeFE(n) - Test whether n is prime using Fermat and Euler pseudoprime tests.
    """
    n = abs(n)
    if n == 1 or n == 0: return False
    if (n in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]): return True
    return isprimeE(n, 2) and isprimeE(n, 3) and isprimeE(n, 5) and isprimeE(n, 7)


def isprimeF(n, b):
    """isprimeF(n,b) - Test whether n is prime or a Fermat pseudoprime to base b."""
    return (pow(b, n - 1, n) == 1)


def isprimeE(n, b):
    """isprimeE(n,b) - Test whether n is prime or an Euler pseudoprime to base b."""
    if (not isprimeF(n, b)): return False
    r = n - 1
    while (r % 2 == 0):
        r //= 2
    c = pow(b, r, n)
    if (c == 1): return True
    while True:
        if (c == 1): return False
        if (c == n - 1): return True
        c = pow(c, 2, n)


from itertools import combinations_with_replacement
from functools import reduce


def toint(lst):
    return reduce(lambda x, y: x * 10 + y, lst)


def runX():
    ndigits = 10
    sum, lower = 0, 10**(ndigits - 1)
    badends = {2, 4, 5, 6, 8, 0}
    for d in range(10):
        Mnd, Snd = 0, ndigits - 1
        while not Mnd:
            for padding in combinations_with_replacement(range(10), ndigits - Snd):
                root = [d] * Snd + list(padding)
                for perm in permutations_wor(root):
                    if not perm[-1] in badends:
                        candidate = toint(perm)
                        if candidate < lower: continue
                        if isprimeFE(candidate):
                            Mnd += 1
                            sum += candidate
            Snd -= 1
    return sum