#fastest code using numba
import numpy as np
from numba import njit

# Given values
x = 2 * 3 * 5 * 7
y = 1/2 + 1/3 + 1/5 + 1/7
equation_lhs = 247 / x
tolerance = 1e-6

@njit
def check_values():
    trueCount = 0
    falseCount = 0
    trueListabcde = []

    for a in range(1, 100):
        for b in range(1, 100):
            for c in range(1, 100):
                for d in range(1, 100):
                    e = x - a - b - c - d
                    equation_rhs = np.sum(np.array([a, b, c, d, e]) / x * np.array([0, 1, 2, 3, 4]))
                    if np.abs(equation_lhs - equation_rhs) < tolerance:
                        trueListabcde.append((a, b, c, d, e))
                        trueCount += 1
                    else:
                        falseCount += 1

    return trueCount, falseCount, trueListabcde

trueCount, falseCount, trueListabcde = check_values()

print("trueCount:", trueCount)
print("falseCount:", falseCount)
print("Length(trueListabcde):", len(trueListabcde))
print("First 10 elements of trueListabcde:", trueListabcde[:10])







#fastest code using numba (longer code that checks more)
#tally of all z/210 for different z, ie 247 for the actual prime factor proportions

import numpy as np
from numba import njit
import matplotlib.pyplot as plt

# Given values
x = 2 * 3 * 5 * 7
y = 1/2 + 1/3 + 1/5 + 1/7
equation_lhs = 247 / x
tolerance = 1e-6
z = 247 / 210
threshold = 0.01  # Adjust the threshold as needed

@njit
def check_values():
    trueCount = 0
    falseCount = 0
    trueListabcde = []
    value_list = []
    value_counts = {}

    for a in range(1, 100):
        for b in range(1, 100):
            for c in range(1, 100):
                for d in range(1, 100):
                    e = x - a - b - c - d
                    equation_rhs = np.sum(np.array([a, b, c, d, e]) / x * np.array([0, 1, 2, 3, 4]))
                    value_list.append(equation_rhs)
                    if np.abs(equation_lhs - equation_rhs) < tolerance:
                        trueListabcde.append((a, b, c, d, e))
                        trueCount += 1
                    else:
                        falseCount += 1
                    if equation_rhs in value_counts:
                        value_counts[equation_rhs] += 1
                    else:
                        value_counts[equation_rhs] = 1

    sorted_counts = sorted(value_counts.items(), key=lambda x: x[1], reverse=True)
    top_10 = sorted_counts[:10]
    bottom_10 = sorted_counts[-10:]

    # Multiply all values by 210
    multiplied_counts = [(value * 210, count) for value, count in sorted_counts]

    # Check how close the results are to being an integer
    close_to_integer = [(value, count) for value, count in multiplied_counts if np.abs(value - np.round(value)) < threshold]

    return trueCount, falseCount, top_10, bottom_10, close_to_integer

trueCount, falseCount, top_10, bottom_10, close_to_integer = check_values()

print("trueCount:", trueCount)
print("falseCount:", falseCount)
print("Top 10 distinct values and their counts:")
for value, count in top_10:
    print(f"{value}: {count}")

print("\nBottom 10 distinct values and their counts:")
for value, count in bottom_10:
    print(f"{value}: {count}")

print("\nValues multiplied by 210 and close to being an integer:")
for value, count in close_to_integer:
    print(f"{value}: {count}")

# Assuming `close_to_integer` is a list of tuples containing values and counts
values = [value for value, _ in close_to_integer]
sorted_values = sorted(values)
sorted_values_rounded = [round(value) for value in sorted_values]

# Tally the occurrence of each integer
value_counts = {}
for value in sorted_values_rounded:
    if value in value_counts:
        value_counts[value] += 1
    else:
        value_counts[value] = 1

print("Sorted values multiplied by 210 and close to being an integer (rounded to nearest integer):")
for value in sorted_values_rounded:
    print(value)

print("\nTally for each integer:")
for value, count in value_counts.items():
    print(f"{value}: {count}")

# Sort the value_counts dictionary by its values
sorted_value_counts = sorted(value_counts.items(), key=lambda x: x[1])

print("\nTop 10 occurring values:")
for value, count in sorted_value_counts[-10:]:
    print(f"{value}: {count}")

print("\nBottom 10 occurring values:")
for value, count in sorted_value_counts[:10]:
    print(f"{value}: {count}")

print("\n10 largest values:")
for value in sorted_values_rounded[-10:]:
    print(value)

print("\n10 smallest values:")
for value in sorted_values_rounded[:10]:
    print(value)

# Sort the value_counts dictionary by its keys
sorted_value_counts = sorted(value_counts.items())
# Extract keys (values) and counts for plotting
keys = [key for key, _ in sorted_value_counts]
counts = [count for _, count in sorted_value_counts]
# Create a bar graph
plt.figure(figsize=(12, 6))
plt.bar(keys, counts, color='skyblue')
plt.xlabel('Integer Values')
plt.ylabel('Counts')
plt.title('Occurrence of Rounded Integer Values')
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()









#slower code using numpy
import numpy as np

# Given values
x = 2 * 3 * 5 * 7
y = 1/2 + 1/3 + 1/5 + 1/7
equation_lhs = 247 / x
tolerance = 1e-6

trueListabcde = []
trueCount = 0
falseCount = 0

for a in range(30, 60):
    for b in range(70, 100):
        for c in range(40, 70):
            for d in range(1, 100):
                e = x - a - b - c - d
                equation_rhs = np.sum(np.array([a, b, c, d, e]) / x * np.array([0, 1, 2, 3, 4]))
                if np.abs(equation_lhs - equation_rhs) < tolerance:
                    trueListabcde.append((a, b, c, d, e))
                    trueCount += 1
                else:
                    falseCount += 1

print("trueCount:", trueCount)
print("falseCount:", falseCount)
print("Length(trueListabcde):", len(trueListabcde))
print("First 10 elements of trueListabcde:", trueListabcde[:10])










#slow code using sympy (for exact rationals)
from sympy import symbols, Rational

# Given values
x = 2 * 3 * 5 * 7
y = Rational(1, 2) + Rational(1, 3) + Rational(1, 5) + Rational(1, 7)

trueListabcde = []
trueCount = 0
falseCount = 0

for a in range(30, 60):
    for b in range(70, 100):
        for c in range(40, 70):
            for d in range(1, 30):
                e = x - a - b - c - d
                equation_lhs = Rational(247, x)
                equation_rhs = Rational(a, x)*0 + Rational(b, x)*1 + Rational(c, x)*2 + Rational(d, x)*3 + Rational(e, x)*4
                if equation_lhs == equation_rhs == y:
                    trueListabcde.append((a, b, c, d, e))
                    trueCount += 1
                else:
                    falseCount += 1

print("trueCount:", trueCount)
print("falseCount:", falseCount)
print("Length(trueListabcde):", len(trueListabcde))
print("First 10 elements of trueListabcde:", trueListabcde[:10])