def non_abundant_sums(pInt):

    lPrimes = utils.sieve_eratosthenes(pInt, pInt)

    lAbundants = []

    for i in range(0, pInt + 1):
        if lPrimes[i] != 1:
            if utils.proper_divisors_sum(i) > i:
                lAbundants.append(i)

    lAbundantSums = np.ones([pInt + 1, ], dtype=np.int)

    for i in lAbundants:
        for j in lAbundants:
            lInt = i + j
            if lInt <= pInt:
                lAbundantSums[lInt] = 0

    lSum = 0

    for i in range(0, pInt + 1):
        if lAbundantSums[i] == 1:
            lSum += i

    return lSum
def goldbachs_other_conjecture(pInt):

    lSieve = sieve_eratosthenes(pInt, pInt)

    for i in range(9, pInt + 1, 2):
        if lSieve[i] == 1:
            continue

        for j in range(2, i + 1):
            if j == i:
                return j

            if lSieve[j] == 0:
                continue

            lInt = i - j

            if (lInt % 2 != 0):
                continue

            lInt = lInt // 2

            if (int(math.sqrt(lInt)) ** 2 == lInt):
                break

    return None
def quadratic_primes(pInt):

    lSieve = sieve_eratosthenes(pInt, pInt)

    lPrimes = []

    for i in range(1, pInt):
        if lSieve[i] == 1:
            lPrimes.append(i)

    lMaxNumPrime = 0
    lMaxA = 0
    lMaxB = 0

    for b in lPrimes:
        for a in range(-pInt, pInt + 1):

            lCurrNumPrime = 0
            lN = 0

            while is_prime(lN * lN + a * lN + b):
                lCurrNumPrime += 1
                lN += 1

            if lCurrNumPrime > lMaxNumPrime:
                lMaxNumPrime = lCurrNumPrime
                lMaxA = a
                lMaxB = b

    return(lMaxA, lMaxB, lMaxNumPrime)
def prime_digit_replacements(pInt):

    lMax = 10 ** 6
    lSieve = sieve_eratosthenes(lMax, lMax)

    lInt = 12

    while (lInt < lMax):
        lInt += 1

        if lSieve[lInt] == 0:
            continue

        lIsDig0 = False
        lIsDig1 = False
        lIsDig2 = False
        lIsDig3 = False

        lStr = str(lInt)

        j = 0

        for i in lStr:
            if i == '0':
                lIsDig0 = True
            elif pInt < 9 and i == '1':
                lIsDig1 = True
            elif pInt < 8 and i == '2':
                lIsDig2 = True
            elif pInt < 7 and i == '3':
                lIsDig3 = True

            j += 1

        if lIsDig0:
            if check_prime(lStr, '0', lSieve) >= pInt:
                return lInt

        if lIsDig1:
            if check_prime(lStr, '1', lSieve) >= pInt:
                return lInt

        if lIsDig2:
            if check_prime(lStr, '2', lSieve) >= pInt:
                return lInt

        if lIsDig3:
            if check_prime(lStr, '3', lSieve) >= pInt:
                return lInt

    return None
def summation_of_primes(pInt):

    if pInt < 2:
        return 0

    lSieve = utils.sieve_eratosthenes(pInt, pInt)

    lSum = 0

    for i in range(1, pInt):
        if lSieve[i] == 1:
            lSum += i

    return lSum
def truncatable_primes(pInt):

    lMax = pInt + 1

    lSieve = sieve_eratosthenes(pInt)

    lNr = 0
    lSum = 0

    for i in range(8, lMax):

        if lSieve[i] == 0:
            continue

        lLen = len(str(i))

        # from left to right ..................................................
        lCount = 0

        for j in range(1, lLen):
            if lSieve[i % (10 ** j)] == 0:
                break
            lCount += 1

        if lCount != lLen - 1:
            continue

        # from right to left ..................................................
        lCount = 0

        for j in range(1, lLen):
            if lSieve[i // (10 ** j)] == 0:
                break
            lCount += 1

        if lCount != lLen - 1:
            continue

        lNr += 1
        lSum += i

#         print(str(lNr) + ': ' + str(i))

    return lSum
def circular_primes(pInt):

    lMax = pInt + 1

    lSieve = sieve_eratosthenes(pInt)

    lCand = []

    for i in range(2, lMax):

        if lSieve[i] == 0:
            continue

        if i <= 11:
            lCand.append(i)
            lSieve[i] = 0
            continue

        lInt = i
        lLen = len(str(i))
        lFact = 10 ** (lLen - 1)
        lCandLoc = []

        for _ in itertools.repeat(None, lLen - 1):
            lInt = (lInt % 10) * lFact + lInt // 10

            if lSieve[lInt] == 0:
                break

            lCandLoc.append(lInt)

        if (lLen != (len(lCandLoc) + 1)):
            continue

        lCand.append(i)

        for k in lCandLoc:
            lCand.append(k)
            lSieve[k] = 0

#     print(str(lCand))

    return len(lCand)
def consecutive_prime_sum(pInt):

    lSieve = sieve_eratosthenes(pInt, pInt)

    lMaxLoop = int(math.sqrt(pInt))
    lMaxPrime = 0
    lMaxPrimeCon = 0

    for i in range(2, lMaxLoop):
        lCurrPrime = 0
        lCurrPrimeCon = 0
        lCurrSum = 0
        lCurrSumCon = 0

        lInt = i

        while (lInt <= pInt):
            if lSieve[lInt] == 1:
                lCurrSumCon += 1
                lCurrSum += lInt

                if lCurrSum > pInt:
                    break

                if lSieve[lCurrSum] == 1:
                    lCurrPrime = lCurrSum
                    lCurrPrimeCon = lCurrSumCon

            lInt += 1

        if lCurrPrimeCon > lMaxPrimeCon:
            lMaxPrime = lCurrPrime
            lMaxPrimeCon = lCurrPrimeCon
            print('con: ' + str(lMaxPrimeCon) + ' prime:' + str(lMaxPrime))

    return lMaxPrime
def prime_permutations():

    lSieve = sieve_eratosthenes(10000, 10000)

    lCand1s = {}

    for i in range(1000, 10000):
        if lSieve[i] == 0:
            continue

        lKey = np.zeros([10, ], dtype=np.int)

        lStr = str(i)

        for c in lStr:
            lKey[int(c)] = 1

        lKeyStr = str(lKey)

        lValues = []

        if lKeyStr in lCand1s:
            lValues = lCand1s.get(lKeyStr)

        lValues.append(i)

        lCand1s[lKeyStr] = lValues

    lCand2s = []

    for i in lCand1s:
        lValues = lCand1s.get(i)
        if len(lValues) > 2:
            lCand2s.append(lValues)

    for i in lCand2s:
        lTop = len(i)

        lSeq = {}

        for j in range(0, lTop - 1):
            for k in range(j + 1, lTop):
                lDiff = i[k] - i[j]

                lDiffs = []

                if lDiff in lSeq:
                    lDiffs = lSeq.get(lDiff)

                if not i[j] in lDiffs:
                    lDiffs.append(i[j])
                if not i[k] in lDiffs:
                    lDiffs.append(i[k])

                lSeq[lDiff] = lDiffs

        for j in lSeq:
            lDiffs = lSeq[j]
            lTop = len(lDiffs)
            if lTop > 2:
                for k in range(0, lTop - 1):
                    if (lDiffs[k + 1] - lDiffs[k] != j):
                        break
                    if k == (lTop - 2):
                        lOut = ''
                        for l in lDiffs:
                            lOut += str(l)
                        print(lOut)
def prime_pair_sets():

    lMaxT = 10 ** 6
    lSieve = sieve_eratosthenes(lMaxT, lMaxT)

    lPrimes = []

    lMaxP = 10 ** 4

    for i in range(1, lMaxT):
        if lSieve[i] == 1:
            lPrimes.append(i)
            if i < lMaxP:
                lMaxPrime = i

    lMaxI = lPrimes.index(lMaxPrime) + 1

    lInts = np.empty(5, dtype='S10')

    for i1 in range(0, lMaxI - 4):
        lPrime1 = lPrimes[i1]
        lInts[0] = str(lPrime1)

        if lPrime1 == 2:
            continue

        if lPrime1 == 5:
            continue

#         print('i1: ' + str(lPrime1))

        for i2 in range(i1 + 1, lMaxI - 3):
            lPrime2 = lPrimes[i2]
            lInts[1] = str(lPrime2)

            if lPrime2 == 5:
                continue

            lInt = int(lInts[0] + lInts[1])

            if lInt > lMaxT:
                if not is_prime(lInt):
                    continue
            elif lSieve[lInt] == 0:
                continue

            lInt = int(lInts[1] + lInts[0])

            if lInt > lMaxT:
                if not is_prime(lInt):
                    continue
            elif lSieve[lInt] == 0:
                continue

#             print('i1: ' + str(lPrime1) + ' i2: ' + str(lPrime2))

            for i3 in range(i2 + 1, lMaxI - 2):
                lPrime3 = lPrimes[i3]
                lInts[2] = str(lPrime3)

                if lPrime3 == 5:
                    continue

                lInt = int(lInts[0] + lInts[2])

                if lInt > lMaxT:
                    if not is_prime(lInt):
                        continue
                elif lSieve[lInt] == 0:
                    continue

                lInt = int(lInts[2] + lInts[0])

                if lInt > lMaxT:
                    if not is_prime(lInt):
                        continue
                elif lSieve[lInt] == 0:
                    continue

                lInt = int(lInts[1] + lInts[2])

                if lInt > lMaxT:
                    if not is_prime(lInt):
                        continue
                elif lSieve[lInt] == 0:
                    continue

                lInt = int(lInts[2] + lInts[1])

                if lInt > lMaxT:
                    if not is_prime(lInt):
                        continue
                elif lSieve[lInt] == 0:
                    continue

#                 print('i1: ' + str(lPrime1) + ' i2: ' + str(lPrime2)
#                                             + ' i3: ' + str(lPrime3))

                for i4 in range(i3 + 1, lMaxI - 1):
                    lPrime4 = lPrimes[i4]
                    lInts[3] = str(lPrime4)

                    lInt = int(lInts[0] + lInts[3])

                    if lInt > lMaxT:
                        if not is_prime(lInt):
                            continue
                    elif lSieve[lInt] == 0:
                        continue

                    lInt = int(lInts[3] + lInts[0])

                    if lInt > lMaxT:
                        if not is_prime(lInt):
                            continue
                    elif lSieve[lInt] == 0:
                        continue

                    lInt = int(lInts[1] + lInts[3])

                    if lInt > lMaxT:
                        if not is_prime(lInt):
                            continue
                    elif lSieve[lInt] == 0:
                        continue

                    lInt = int(lInts[3] + lInts[1])

                    if lInt > lMaxT:
                        if not is_prime(lInt):
                            continue
                    elif lSieve[lInt] == 0:
                        continue

                    lInt = int(lInts[2] + lInts[3])

                    if lInt > lMaxT:
                        if not is_prime(lInt):
                            continue
                    elif lSieve[lInt] == 0:
                        continue

                    lInt = int(lInts[3] + lInts[2])

                    if lInt > lMaxT:
                        if not is_prime(lInt):
                            continue
                    elif lSieve[lInt] == 0:
                        continue

#                     print('i1: ' + str(lPrime1) + ' i2: ' + str(lPrime2)
#                                                 + ' i3: ' + str(lPrime3)
#                                                 + ' i4: ' + str(lPrime4))

                    for i5 in range(i4 + 1, lMaxI):
                        lPrime5 = lPrimes[i5]
                        lInts[4] = str(lPrime5)

                        lInt = int(lInts[0] + lInts[4])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[4] + lInts[0])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[1] + lInts[4])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[4] + lInts[1])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[2] + lInts[4])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[4] + lInts[2])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[3] + lInts[4])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

                        lInt = int(lInts[4] + lInts[3])

                        if lInt > lMaxT:
                            if not is_prime(lInt):
                                continue
                        elif lSieve[lInt] == 0:
                            continue

#                         print('i1: ' + str(lPrime1) + ' i2: ' + str(lPrime2)
#                                                     + ' i3: ' + str(lPrime3)
#                                                     + ' i4: ' + str(lPrime4)
#                                                     + ' i5: ' + str(lPrime5))

                        return (lPrime1 + lPrime2 + lPrime3
                                        + lPrime4 + lPrime5)
    return None
def distinct_primes_factors():

    lMaxDigits = 4
    lMaxPrimes = 10 ** 5

    lSieve = sieve_eratosthenes(lMaxPrimes, lMaxPrimes)

    lInt = 5

    while (True):
        lInt += 1

        lFactors = divisors_all_distinct_non_trivial(lInt)

        if len(lFactors) < lMaxDigits:
            continue

        lPrimes = 0

        for i in lFactors:
            if lSieve[i] == 1:
                lPrimes += 1

        if lPrimes != lMaxDigits:
            continue

        lFactors = divisors_all_distinct_non_trivial(lInt + 1)

        if len(lFactors) < lMaxDigits:
            continue

        lPrimes = 0

        for i in lFactors:
            if lSieve[i] == 1:
                lPrimes += 1

        if lPrimes != lMaxDigits:
            continue

        lFactors = divisors_all_distinct_non_trivial(lInt + 2)

        if len(lFactors) < lMaxDigits:
            continue

        lPrimes = 0

        for i in lFactors:
            if lSieve[i] == 1:
                lPrimes += 1

        if lPrimes != lMaxDigits:
            continue

#         print('3: ' + str(lInt))

        lFactors = divisors_all_distinct_non_trivial(lInt + 3)

        if len(lFactors) < lMaxDigits:
            continue

        lPrimes = 0

        for i in lFactors:
            if lSieve[i] == 1:
                lPrimes += 1

        if lPrimes == lMaxDigits:
            return lInt