A Python library implementing prime detection using integer partitions, based on the 2023 paper "Integer Partitions Detect the Primes" by William Craig, Jan-Willem van Ittersum, and Ken Ono.
- Background
- The Mathematics
- Installation
- Quick Start
- API Reference
- Examples
- Performance
- Project Structure
- Running Tests
- Contributing
- Roadmap
- References
- License
In 2023, mathematicians William Craig, Jan-Willem van Ittersum, and Ken Ono published a groundbreaking paper demonstrating that the prime numbers can be detected purely through integer partition theory — a branch of mathematics historically unconnected to primality.
This was a surprise to the mathematical community. For centuries, partitions and primes were considered separate domains. Ono's team found a precise algebraic identity involving MacMahon-style partition functions that equals zero if and only if a given integer is prime.
This library is a Python implementation of those ideas, designed for:
- Mathematical experimentation with partition-based primality
- Education — understanding the connection between partitions and primes
- Research — a foundation for exploring faster variants of the MacMahon functions
- Benchmarking — comparing partition-based detection against classical methods
A partition of an integer n is a way of writing n as an unordered sum of positive
integers. For example, the partitions of 5 are:
5
4 + 1
3 + 2
3 + 1 + 1
2 + 2 + 1
2 + 1 + 1 + 1
1 + 1 + 1 + 1 + 1
MacMahon studied weighted sums over partitions, where the weight is a product of
multiplicities of part sizes. In a partition, if part size s appears m times,
then m is the multiplicity of s.
The key functions in this library are:
M1(n) — Weighted sum over partitions with a single distinct part size:
M1(n) = Σ m over all partitions (m, s) where m*s = n
This is equivalent to the classical sum-of-divisors function σ₁(n):
M1(6) = 1 + 2 + 3 + 6 = 12
M2(n) — Weighted sum over partitions with exactly two distinct part sizes:
M2(n) = Σ (m1 * m2) over all partitions m1*s1 + m2*s2 = n
where s1 < s2, m1 >= 1, m2 >= 1
Example for n = 6:
Partition 1*1 + 1*5 = 6 → m1=1, m2=1 → contributes 1*1 = 1
Partition 2*1 + 1*4 = 6 → m1=2, m2=1 → contributes 2*1 = 2
Partition 1*2 + 1*4 = 6 → m1=1, m2=1 → contributes 1*1 = 1
...
M2(6) = 4
The central theorem of the paper states:
For any integer
n ≥ 2,nis prime if and only if:(n² - 3n + 2) · M1(n) - 8 · M2(n) = 0
This is an exact algebraic identity — not a probabilistic test, not an approximation.
When the left-hand side evaluates to exactly zero, n is guaranteed to be prime.
Worked example for n = 7 (prime):
M1(7) = 1 + 7 = 8
M2(7) = 8
(7² - 3·7 + 2) · M1(7) - 8 · M2(7)
= (49 - 21 + 2) · 8 - 8 · 8
= 30 · 8 - 64
= 240 - 240
= 0 ✓ (prime)
Worked example for n = 4 (composite):
M1(4) = 1 + 2 + 4 = 7
M2(4) = 2
(4² - 3·4 + 2) · M1(4) - 8 · M2(4)
= (16 - 12 + 2) · 7 - 8 · 2
= 6 · 7 - 16
= 42 - 16
= 26 ≠ 0 (composite)
Classical primality tests like trial division or Miller-Rabin work by attempting to find factors. The Ono-Craig-van Ittersum result works by an entirely different mechanism — it counts weighted partition structures.
The mathematical significance is profound:
- It unifies two separate areas of number theory — partition theory and prime detection
- It is an exact identity, not an asymptotic or probabilistic result
- It opens a new research direction: if a MacMahon function variant can be computed
in
O(log n)time, it could become the foundation of new cryptographic algorithms
Important: It is strongly recommended to install this library inside a virtual environment to avoid conflicts with your system Python packages.
# Navigate to your project directory
cd ono-primes
# Create a virtual environment named .venv
python -m venv .venv
# Activate the virtual environment
# Command Prompt:
.venv\Scripts\activate.bat
# PowerShell:
.venv\Scripts\Activate.ps1PowerShell Note: If you get an execution policy error, run this first:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Navigate to your project directory
cd ono-primes
# Create a virtual environment named .venv
python3 -m venv .venv
# Activate the virtual environment
source .venv/bin/activateOnce activated, your terminal prompt will show (.venv) as a prefix:
(.venv) PS C:\Users\yourname\code\repos\ono-primes>You can also verify which Python is being used:
# Windows
where python
# macOS / Linux
which python
# Should point to .venv/bin/python or .venv\Scripts\python.exeWhen you are done working on the project:
deactivateWith your virtual environment activated, clone and install the library:
# Clone the repository
git clone https://github.com/yourusername/ono-primes.git
cd ono-primes
# Create and activate the virtual environment (see above)
python -m venv .venv
.venv\Scripts\activate.bat # Windows
# or
source .venv/bin/activate # macOS / Linux
# Install the library in editable mode with all dependencies
pip install -e .To confirm the installation was successful:
pip show ono-primes| Package | Version | Purpose |
|---|---|---|
sympy |
>=1.10 |
Divisor computation, validation |
| Python | >=3.10 |
Type hints, match statements |
All dependencies are installed automatically via pip install -e .
To install dependencies manually inside your virtual environment:
pip install -r requirements.txtTo see all currently installed packages in your virtual environment:
pip listWith your virtual environment activated:
from ono_primes import is_prime_ono, M1, M2
# Check if a number is prime
print(is_prime_ono(7)) # True
print(is_prime_ono(8)) # False
# Inspect the partition functions
print(M1(7)) # 8
print(M2(7)) # 8
# Get all primes up to 50
from ono_primes import primes_up_to
print(primes_up_to(50))
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]from ono_primes.partitions import M1
M1(n: int) -> intCalculates the sum of all divisors of n. Equivalent to the classical sigma function
σ₁(n). Results are cached automatically with lru_cache.
| Parameter | Type | Description |
|---|---|---|
n |
int |
A positive integer ≥ 1 |
Returns: int — The sum of all divisors of n.
Raises: ValueError if n < 1.
M1(1) # 1
M1(6) # 12 (1 + 2 + 3 + 6)
M1(7) # 8 (1 + 7)
M1(12) # 28 (1 + 2 + 3 + 4 + 6 + 12)from ono_primes.partitions import M2
M2(n: int) -> intCalculates the MacMahon M2 function: the sum of products (m1 * m2) over all
two-part partitions n = m1·s1 + m2·s2 where s1 < s2. Results are cached.
| Parameter | Type | Description |
|---|---|---|
n |
int |
A positive integer ≥ 1 |
Returns: int — The M2 value for n.
Raises: ValueError if n < 1.
M2(6) # 4
M2(7) # 8
M2(12) # ...from ono_primes.partitions import partition_summary
partition_summary(n: int) -> dictReturns a dictionary summary of all partition function values for n.
partition_summary(6)
# {'n': 6, 'M1': 12, 'M2': 4}from ono_primes.prime_detection import is_prime_ono
is_prime_ono(n: int) -> boolReturns True if n is prime using the Ono-Craig-van Ittersum equation.
| Parameter | Type | Description |
|---|---|---|
n |
int |
Any integer |
Returns: bool
Raises: TypeError if n is not an integer.
is_prime_ono(2) # True
is_prime_ono(7) # True
is_prime_ono(1) # False
is_prime_ono(100) # Falsefrom ono_primes.prime_detection import prime_indicator
prime_indicator(n: int) -> intReturns the raw value of the Ono equation for n. A return value of 0 means n
is prime. The magnitude of non-zero values has no standard interpretation but can
be explored mathematically.
prime_indicator(7) # 0 (prime)
prime_indicator(8) # 48 (composite)
prime_indicator(4) # 26 (composite)from ono_primes.prime_detection import primes_up_to
primes_up_to(limit: int) -> list[int]Returns a list of all prime numbers up to and including limit.
primes_up_to(30)
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]from ono_primes.prime_detection import prime_generator
prime_generator(start: int = 2) -> Generator[int, None, None]An infinite generator that yields prime numbers starting from start.
gen = prime_generator()
[next(gen) for _ in range(10)]
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
gen = prime_generator(start=100)
next(gen) # 101from ono_primes.utils import benchmark
benchmark(n: int) -> dictBenchmarks the Ono method against SymPy's isprime for a single value of n.
benchmark(13)
# {
# 'n': 13,
# 'ono_result': True,
# 'sympy_result': True,
# 'results_match': True,
# 'ono_time_seconds': 0.000412,
# 'sympy_time_seconds': 0.000003,
# 'speedup_factor': 137.3
# }from ono_primes.utils import validate_range
validate_range(low: int, high: int) -> dictValidates the Ono method against SymPy's isprime over a range of integers.
Returns a summary of any disagreements and total timing.
validate_range(2, 100)
# {
# 'range': (2, 100),
# 'all_match': True,
# 'disagreements': [],
# 'total_ono_time_seconds': 1.234,
# 'total_sympy_time_seconds': 0.002
# }from ono_primes.utils import equation_table
equation_table(low: int, high: int) -> list[dict]Returns a table of raw equation values for a range of integers. Useful for mathematical exploration.
equation_table(2, 8)
# [
# {'n': 2, 'indicator': 0, 'is_prime': True},
# {'n': 3, 'indicator': 0, 'is_prime': True},
# {'n': 4, 'indicator': 26, 'is_prime': False},
# {'n': 5, 'indicator': 0, 'is_prime': True},
# {'n': 6, 'indicator': 32, 'is_prime': False},
# {'n': 7, 'indicator': 0, 'is_prime': True},
# {'n': 8, 'indicator': 48, 'is_prime': False},
# ]from ono_primes import is_prime_ono
for n in range(2, 30):
if is_prime_ono(n):
print(n, end=" ")
# 2 3 5 7 11 13 17 19 23 29from ono_primes.prime_detection import prime_generator
gen = prime_generator()
primes = [next(gen) for _ in range(20)]
print(primes)
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]from ono_primes.partitions import M1, M2, partition_summary
for n in range(2, 15):
s = partition_summary(n)
print(f"n={n:3d} M1={s['M1']:4d} M2={s['M2']:4d}")%matplotlib widget # for interactive rotation in Jupyter
from ono_primes import plot_fermats_spiral_3d
ax = plot_fermats_spiral_3d(
n_max=1500,
radial_scale=0.08,
z_scale=0.01,
)Fermat vs Logarithmic Spiral of Integers
Each dot represents an integer (n = 1, 2, 3, ...).
- Gray and green dots are composite numbers.
- Pink and gold dots are prime numbers.
The lower (pink/gray) layer is the 3D Fermat (golden‑angle) spiral of the integers:
where
and
The upper (gold/green) layer is the 3D logarithmic spiral of the integers:
where
in the code, and
is a constant vertical offset so the log spiral floats above the Fermat spiral.
from ono_primes.utils import benchmark
for n in [7, 13, 29, 50]:
r = benchmark(n)
print(f"n={n:3d} ono={r['ono_time_seconds']:.5f}s "
f"sympy={r['sympy_time_seconds']:.5f}s "
f"match={r['results_match']}")from ono_primes.utils import validate_range
result = validate_range(2, 50)
print(f"All results match SymPy: {result['all_match']}")
print(f"Total Ono time: {result['total_ono_time_seconds']:.4f}s")
print(f"Total SymPy time: {result['total_sympy_time_seconds']:.4f}s")| Function | Time Complexity | Notes |
|---|---|---|
M1(n) |
O(√n) |
Via SymPy's divisor function |
M2(n) |
O(n³) approx |
Triple nested loop |
is_prime_ono(n) |
Dominated by M2(n) |
See above |
Both M1(n) and M2(n) use Python's functools.lru_cache with unlimited size.
Repeated calls with the same n are essentially free after the first computation.
import time
from ono_primes.partitions import M2
# First call — computed fresh
start = time.perf_counter()
M2(30)
print(f"First call: {time.perf_counter() - start:.5f}s")
# Second call — served from cache
start = time.perf_counter()
M2(30)
print(f"Cached call: {time.perf_counter() - start:.5f}s")- Not suitable for large n in the current implementation. The triple nested loop in
M2(n)grows very quickly. Forn > 50, computation time becomes significant. - Research use only — classical primality tests (
sympy.isprime,gmpy2) are orders of magnitude faster for production use. - Future work: The paper suggests that alternative MacMahon function forms may yield faster algorithms. This library is a foundation for that research.
ono_primes/
├── __init__.py # Public API surface
├── partitions.py # M1(n), M2(n), partition_summary(n)
├── prime_detection.py # is_prime_ono, prime_indicator, primes_up_to, prime_generator
├── utils.py # benchmark, validate_range, equation_table
├── tests/
│ ├── __init__.py
│ ├── test_partitions.py # Tests for M1, M2, partition_summary
│ ├── test_prime_detection.py # Tests for is_prime_ono, prime_indicator, etc.
│ └── test_utils.py # Tests for benchmark, validate_range, etc.
├── examples/
│ └── example_usage.py # Runnable demonstration script
├── .venv/ # Virtual environment (not committed to git)
├── .gitignore
├── README.md
├── setup.py
└── requirements.txt
Ensure your virtual environment is activated before running tests.
Run the full test suite with:
python -m unittest discover -s ono_primes/tests -vRun a specific test file:
python -m unittest ono_primes.tests.test_partitions -v
python -m unittest ono_primes.tests.test_prime_detection -v
python -m unittest ono_primes.tests.test_utils -vRun the example script:
python ono_primes/examples/example_usage.pyContributions are welcome, especially in the following areas:
- Performance optimizations for
M2(n)— algorithmic improvements, NumPy vectorization, or Cython extensions - Higher-order MacMahon functions — implementing
M3(n),M4(n), etc. from the paper's more general framework - Alternative prime equations — the paper contains multiple partition-based identities; implementing and testing additional ones
- Documentation — mathematical explanations, Jupyter notebook tutorials
To contribute:
# Clone and set up your virtual environment
git clone https://github.com/yourusername/ono-primes.git
cd ono-primes
python -m venv .venv
.venv\Scripts\activate.bat # Windows
source .venv/bin/activate # macOS / Linux
pip install -e .
# Make your changes, add tests, then open a pull requestNote: Never commit your
.venv/folder. Add it to.gitignore:.venv/ __pycache__/ *.pyc *.egg-info/ dist/ build/
- v0.1.0 — Core
M1,M2, andis_prime_onoimplementation - v0.2.0 — Implement
M3(n)andM4(n)from the paper - v0.3.0 — NumPy-accelerated partition enumeration
- v0.4.0 — Jupyter notebook tutorials and mathematical documentation
- v0.5.0 — Explore and implement any known
O(n log n)shortcuts - v1.0.0 — Stable API, full documentation, PyPI release
-
Craig, W., van Ittersum, J.-W., & Ono, K. (2023). Integer Partitions Detect the Primes. arXiv:2301.XXXXX
-
MacMahon, P.A. (1916). Combinatory Analysis, Volumes I and II. Cambridge University Press.
-
Andrews, G.E. (1998). The Theory of Partitions. Cambridge University Press.
-
SymPy Development Team (2023). SymPy: Python library for symbolic mathematics. https://www.sympy.org
