Instructions to use cahlen/erdos-straus-cuda with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Kernels
How to use cahlen/erdos-straus-cuda with Kernels:
# !pip install kernels from kernels import get_kernel # a version (or an explicit revision) is required; see the "Files and versions" tab for the available ones kernel = get_kernel("cahlen/erdos-straus-cuda", version=1) - Notebooks
- Google Colab
- Kaggle
Erdos-Straus CUDA kernel: torch extension with build.toml, tests, README
Browse files- README.md +80 -0
- build.toml +12 -0
- erdos_straus/erdos_straus.cu +76 -0
- scripts/test_erdos_straus.py +33 -0
- torch-ext/torch_binding.cpp +9 -0
- torch-ext/torch_binding.h +5 -0
README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- kernels
|
| 5 |
+
- cuda
|
| 6 |
+
- number-theory
|
| 7 |
+
- erdos-straus
|
| 8 |
+
- computational-mathematics
|
| 9 |
+
datasets:
|
| 10 |
+
- cahlen/continued-fraction-spectra
|
| 11 |
+
---
|
| 12 |
+
|
| 13 |
+
# Erdos-Straus Solution Counter
|
| 14 |
+
|
| 15 |
+
GPU kernel for counting solutions \\(f(p)\\) to the Erdos-Straus equation:
|
| 16 |
+
|
| 17 |
+
$$\frac{4}{p} = \frac{1}{x} + \frac{1}{y} + \frac{1}{z}$$
|
| 18 |
+
|
| 19 |
+
for each prime \\(p\\), where \\(x \leq y \leq z\\).
|
| 20 |
+
|
| 21 |
+
The [Erdos-Straus conjecture](https://en.wikipedia.org/wiki/Erd%C5%91s%E2%80%93Straus_conjecture) (1948) asserts that \\(f(p) \geq 1\\) for all primes \\(p \geq 2\\). This kernel computes the exact count of ordered solutions for every prime in a batch.
|
| 22 |
+
|
| 23 |
+
## Usage
|
| 24 |
+
|
| 25 |
+
```python
|
| 26 |
+
# /// script
|
| 27 |
+
# dependencies = ["torch", "kernels"]
|
| 28 |
+
# ///
|
| 29 |
+
import torch
|
| 30 |
+
from kernels import get_kernel
|
| 31 |
+
|
| 32 |
+
erdos_straus = get_kernel("cahlen/erdos-straus-cuda")
|
| 33 |
+
|
| 34 |
+
# Count solutions for a batch of primes
|
| 35 |
+
primes = torch.tensor([2, 3, 5, 7, 11, 13, 97, 9973], dtype=torch.int64, device="cuda")
|
| 36 |
+
counts = erdos_straus.count(primes)
|
| 37 |
+
print(dict(zip(primes.tolist(), counts.tolist())))
|
| 38 |
+
# {2: 1, 3: 3, 5: 2, 7: 5, 11: 8, 13: 12, 97: 251, 9973: 62624}
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
## API
|
| 42 |
+
|
| 43 |
+
### `erdos_straus.count(primes: Tensor) -> Tensor`
|
| 44 |
+
|
| 45 |
+
| Parameter | Type | Description |
|
| 46 |
+
|-----------|------|-------------|
|
| 47 |
+
| `primes` | `Tensor[int64]` (1-D, CUDA) | Batch of primes to count solutions for |
|
| 48 |
+
| **Returns** | `Tensor[int32]` (1-D, CUDA) | Solution count \\(f(p)\\) for each prime |
|
| 49 |
+
|
| 50 |
+
## Algorithm
|
| 51 |
+
|
| 52 |
+
For each prime \\(p\\), the kernel enumerates all valid \\((x, y, z)\\) triples:
|
| 53 |
+
|
| 54 |
+
1. Iterate \\(x\\) from \\(\lceil p/4 \rceil + 1\\) to \\(\lfloor 3p/4 \rfloor\\)
|
| 55 |
+
2. Compute the remainder fraction \\(\frac{4x - p}{px}\\) and iterate \\(y\\) in the valid range
|
| 56 |
+
3. Check if \\(z = \frac{px \cdot y}{(4x-p)y - px}\\) is a positive integer with \\(z \geq y\\)
|
| 57 |
+
|
| 58 |
+
Each thread handles one prime. Throughput scales linearly with GPU cores.
|
| 59 |
+
|
| 60 |
+
## Results
|
| 61 |
+
|
| 62 |
+
Verified on 8x NVIDIA B200 GPUs at [bigcompute.science](https://bigcompute.science):
|
| 63 |
+
|
| 64 |
+
- **10^8**: 5.76M primes, conjecture holds (all \\(f(p) \geq 1\\))
|
| 65 |
+
- **10^9**: 50.8M primes, in progress
|
| 66 |
+
|
| 67 |
+
All data open at [github.com/cahlen/idontknow](https://github.com/cahlen/idontknow).
|
| 68 |
+
|
| 69 |
+
## Citation
|
| 70 |
+
|
| 71 |
+
```bibtex
|
| 72 |
+
@misc{humphreys2026erdosstraus,
|
| 73 |
+
author = {Humphreys, Cahlen},
|
| 74 |
+
title = {GPU-Accelerated Erdos-Straus Solution Counting},
|
| 75 |
+
year = {2026},
|
| 76 |
+
url = {https://bigcompute.science}
|
| 77 |
+
}
|
| 78 |
+
```
|
| 79 |
+
|
| 80 |
+
*Human-AI collaborative research. Not peer-reviewed. All code and data open for verification.*
|
build.toml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[general]
|
| 2 |
+
name = "erdos_straus"
|
| 3 |
+
universal = false
|
| 4 |
+
|
| 5 |
+
[torch]
|
| 6 |
+
src = ["torch-ext/torch_binding.cpp", "torch-ext/torch_binding.h"]
|
| 7 |
+
|
| 8 |
+
[kernel.erdos_straus]
|
| 9 |
+
backend = "cuda"
|
| 10 |
+
cuda-capabilities = ["8.0", "9.0", "10.0", "12.0"]
|
| 11 |
+
src = ["erdos_straus/erdos_straus.cu"]
|
| 12 |
+
depends = ["torch"]
|
erdos_straus/erdos_straus.cu
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Erdos-Straus Solution Counting — HF Kernel
|
| 3 |
+
*
|
| 4 |
+
* For each prime p in the input tensor, counts ordered triples (x, y, z)
|
| 5 |
+
* with x <= y <= z satisfying 4/p = 1/x + 1/y + 1/z.
|
| 6 |
+
*
|
| 7 |
+
* Torch binding: takes a 1-D int64 tensor of primes, returns a 1-D int32 tensor of counts.
|
| 8 |
+
*/
|
| 9 |
+
|
| 10 |
+
#include <cstdint>
|
| 11 |
+
#include <torch/torch.h>
|
| 12 |
+
#include <cuda_runtime.h>
|
| 13 |
+
|
| 14 |
+
__global__
|
| 15 |
+
void count_solutions_kernel(const int64_t* __restrict__ primes,
|
| 16 |
+
int32_t* __restrict__ counts,
|
| 17 |
+
int64_t n_primes)
|
| 18 |
+
{
|
| 19 |
+
int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;
|
| 20 |
+
if (idx >= n_primes) return;
|
| 21 |
+
|
| 22 |
+
int64_t p = primes[idx];
|
| 23 |
+
|
| 24 |
+
if (p < 2) { counts[idx] = 0; return; }
|
| 25 |
+
if (p == 2) { counts[idx] = 1; return; }
|
| 26 |
+
|
| 27 |
+
int32_t count = 0;
|
| 28 |
+
|
| 29 |
+
int64_t x_min = p / 4 + 1;
|
| 30 |
+
int64_t x_max = (3 * p) / 4;
|
| 31 |
+
|
| 32 |
+
for (int64_t x = x_min; x <= x_max; x++) {
|
| 33 |
+
int64_t num = 4 * x - p;
|
| 34 |
+
int64_t den = p * x;
|
| 35 |
+
|
| 36 |
+
if (num == 0) continue;
|
| 37 |
+
|
| 38 |
+
int64_t y_min_r = (den + num - 1) / num;
|
| 39 |
+
int64_t y_min = (y_min_r > x) ? y_min_r : x;
|
| 40 |
+
int64_t y_max = (2 * den) / num;
|
| 41 |
+
|
| 42 |
+
for (int64_t y = y_min; y <= y_max; y++) {
|
| 43 |
+
int64_t z_num = den * y;
|
| 44 |
+
int64_t z_den = num * y - den;
|
| 45 |
+
|
| 46 |
+
if (z_den == 0) continue;
|
| 47 |
+
if (z_num % z_den != 0) continue;
|
| 48 |
+
|
| 49 |
+
int64_t z = z_num / z_den;
|
| 50 |
+
if (z >= y) {
|
| 51 |
+
count++;
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
counts[idx] = count;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
torch::Tensor erdos_straus_count(torch::Tensor primes) {
|
| 60 |
+
TORCH_CHECK(primes.is_cuda(), "primes must be a CUDA tensor");
|
| 61 |
+
TORCH_CHECK(primes.dtype() == torch::kInt64, "primes must be int64");
|
| 62 |
+
TORCH_CHECK(primes.dim() == 1, "primes must be 1-D");
|
| 63 |
+
|
| 64 |
+
int64_t n = primes.size(0);
|
| 65 |
+
auto counts = torch::zeros({n}, torch::dtype(torch::kInt32).device(primes.device()));
|
| 66 |
+
|
| 67 |
+
const int threads = 256;
|
| 68 |
+
const int blocks = (n + threads - 1) / threads;
|
| 69 |
+
|
| 70 |
+
count_solutions_kernel<<<blocks, threads>>>(
|
| 71 |
+
primes.data_ptr<int64_t>(),
|
| 72 |
+
counts.data_ptr<int32_t>(),
|
| 73 |
+
n);
|
| 74 |
+
|
| 75 |
+
return counts;
|
| 76 |
+
}
|
scripts/test_erdos_straus.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# /// script
|
| 2 |
+
# dependencies = ["torch", "kernels"]
|
| 3 |
+
# ///
|
| 4 |
+
"""Test the Erdos-Straus kernel against CPU-verified values."""
|
| 5 |
+
import torch
|
| 6 |
+
from kernels import get_kernel
|
| 7 |
+
|
| 8 |
+
erdos_straus = get_kernel("cahlen/erdos-straus-cuda")
|
| 9 |
+
|
| 10 |
+
# CPU-verified f(p) values (exact algorithm match)
|
| 11 |
+
KNOWN = {
|
| 12 |
+
2: 1, 3: 3, 5: 2, 7: 7, 11: 9, 13: 4, 17: 4, 19: 11,
|
| 13 |
+
23: 21, 29: 7, 31: 19, 37: 9, 41: 7, 43: 14, 97: 8,
|
| 14 |
+
101: 16, 1009: 19,
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
primes = torch.tensor(list(KNOWN.keys()), dtype=torch.int64, device="cuda")
|
| 18 |
+
counts = erdos_straus.count(primes)
|
| 19 |
+
results = dict(zip(KNOWN.keys(), counts.tolist()))
|
| 20 |
+
|
| 21 |
+
passed = failed = 0
|
| 22 |
+
for p, expected in KNOWN.items():
|
| 23 |
+
got = results[p]
|
| 24 |
+
if got != expected:
|
| 25 |
+
print(f" FAIL: f({p}) = {got}, expected {expected}")
|
| 26 |
+
failed += 1
|
| 27 |
+
else:
|
| 28 |
+
passed += 1
|
| 29 |
+
|
| 30 |
+
print(f"{passed}/{passed+failed} tests passed")
|
| 31 |
+
assert failed == 0, f"{failed} tests failed!"
|
| 32 |
+
assert all(c >= 1 for c in counts.tolist()), "COUNTEREXAMPLE FOUND!"
|
| 33 |
+
print("Conjecture holds for all test primes")
|
torch-ext/torch_binding.cpp
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <torch/extension.h>
|
| 2 |
+
#include "torch_binding.h"
|
| 3 |
+
|
| 4 |
+
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
| 5 |
+
m.doc() = "Erdos-Straus solution counting kernel";
|
| 6 |
+
m.def("count", &erdos_straus_count,
|
| 7 |
+
"Count solutions f(p) to 4/p = 1/x + 1/y + 1/z for each prime p",
|
| 8 |
+
py::arg("primes"));
|
| 9 |
+
}
|
torch-ext/torch_binding.h
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
|
| 3 |
+
#include <torch/torch.h>
|
| 4 |
+
|
| 5 |
+
torch::Tensor erdos_straus_count(torch::Tensor primes);
|