Instructions to use cahlen/ramanujan-machine-cuda with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Kernels
How to use cahlen/ramanujan-machine-cuda with Kernels:
# !pip install kernels from kernels import get_kernel kernel = get_kernel("cahlen/ramanujan-machine-cuda") - Notebooks
- Google Colab
- Kaggle
CUDA kernel: ramanujan-machine-cuda
Browse files- README.md +52 -0
- build.toml +12 -0
- ramanujan/ramanujan_v2.cu +536 -0
- scripts/test.py +31 -0
- torch-ext/torch_binding.cpp +6 -0
- torch-ext/torch_binding.h +3 -0
README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
tags:
|
| 4 |
+
- kernels
|
| 5 |
+
- cuda
|
| 6 |
+
- ramanujan-machine
|
| 7 |
+
- continued-fractions
|
| 8 |
+
- mathematical-constants
|
| 9 |
+
- number-theory
|
| 10 |
+
datasets:
|
| 11 |
+
- cahlen/ramanujan-machine-results
|
| 12 |
+
---
|
| 13 |
+
|
| 14 |
+
# Ramanujan Machine v2 (Asymmetric-Degree CF Search)
|
| 15 |
+
|
| 16 |
+
Searches for polynomial continued fraction formulas with asymmetric degrees. Evaluates CF candidates and matches against known mathematical constants.
|
| 17 |
+
|
| 18 |
+
## Usage
|
| 19 |
+
|
| 20 |
+
```python
|
| 21 |
+
import torch
|
| 22 |
+
from kernels import get_kernel
|
| 23 |
+
|
| 24 |
+
kernel = get_kernel("cahlen/ramanujan-machine-cuda")
|
| 25 |
+
result = ramanujan.search(deg_a=1, deg_b=2, range_a=10, range_b=10)
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
## Compile (standalone)
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
nvcc -O3 -arch=sm_90 -o ramanujan_machine ramanujan/ramanujan_v2.cu -lm
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
## Results
|
| 35 |
+
|
| 36 |
+
All computation results are open:
|
| 37 |
+
- **Website**: [bigcompute.science](https://bigcompute.science)
|
| 38 |
+
- **Datasets**: [huggingface.co/cahlen](https://huggingface.co/cahlen)
|
| 39 |
+
- **Source**: [github.com/cahlen/idontknow](https://github.com/cahlen/idontknow)
|
| 40 |
+
|
| 41 |
+
## Citation
|
| 42 |
+
|
| 43 |
+
```bibtex
|
| 44 |
+
@misc{humphreys2026bigcompute,
|
| 45 |
+
author = {Humphreys, Cahlen},
|
| 46 |
+
title = {bigcompute.science: GPU-Accelerated Computational Mathematics},
|
| 47 |
+
year = {2026},
|
| 48 |
+
url = {https://bigcompute.science}
|
| 49 |
+
}
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
*Human-AI collaborative. Not peer-reviewed. All code and data open.*
|
build.toml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[general]
|
| 2 |
+
name = "ramanujan_machine"
|
| 3 |
+
universal = false
|
| 4 |
+
|
| 5 |
+
[torch]
|
| 6 |
+
src = ["torch-ext/torch_binding.cpp", "torch-ext/torch_binding.h"]
|
| 7 |
+
|
| 8 |
+
[kernel.ramanujan_machine]
|
| 9 |
+
backend = "cuda"
|
| 10 |
+
cuda-capabilities = ["8.0", "9.0", "10.0", "12.0"]
|
| 11 |
+
src = ["ramanujan/ramanujan_v2.cu"]
|
| 12 |
+
depends = ["torch"]
|
ramanujan/ramanujan_v2.cu
ADDED
|
@@ -0,0 +1,536 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Ramanujan Machine v2: ASYMMETRIC-DEGREE polynomial CF search
|
| 3 |
+
*
|
| 4 |
+
* KEY INSIGHT: Every known CF formula for transcendental constants has
|
| 5 |
+
* deg(b_n) ≈ 2 * deg(a_n). v1 forced equal degrees, which is why it
|
| 6 |
+
* only re-derived classical formulas and produced zero new transcendentals.
|
| 7 |
+
*
|
| 8 |
+
* CF = a(0) + b(1) / (a(1) + b(2) / (a(2) + b(3) / (a(3) + ...)))
|
| 9 |
+
* a(n) = polynomial of degree deg_a, coefficients in [-range_a, range_a]
|
| 10 |
+
* b(n) = polynomial of degree deg_b, coefficients in [-range_b, range_b]
|
| 11 |
+
*
|
| 12 |
+
* Productive search targets (deg_a, deg_b):
|
| 13 |
+
* (1, 2) — Brouncker/Wallis family (4/pi, etc.)
|
| 14 |
+
* (2, 4) — Catalan/zeta(2) family
|
| 15 |
+
* (3, 6) — Apéry family (zeta(3), zeta(5))
|
| 16 |
+
* (2, 3) — sub-ratio region, still productive
|
| 17 |
+
* (1, 3) — mixed regime
|
| 18 |
+
*
|
| 19 |
+
* Also outputs ALL converged CFs (not just matched ones) to enable
|
| 20 |
+
* offline multi-constant PSLQ scanning.
|
| 21 |
+
*
|
| 22 |
+
* Compile: nvcc -O3 -arch=sm_100a -o ramanujan_v2 ramanujan_v2.cu -lm
|
| 23 |
+
* Run: ./ramanujan_v2 <deg_a> <deg_b> <range_a> <range_b> [cf_depth] [gpu_id]
|
| 24 |
+
*
|
| 25 |
+
* Examples:
|
| 26 |
+
* ./ramanujan_v2 2 4 6 6 # Catalan-type, 1.7T candidates
|
| 27 |
+
* ./ramanujan_v2 1 2 10 10 # Brouncker-type, 194M candidates
|
| 28 |
+
* ./ramanujan_v2 3 6 3 3 # Apéry-type, 282B candidates
|
| 29 |
+
*/
|
| 30 |
+
|
| 31 |
+
#include <stdio.h>
|
| 32 |
+
#include <stdlib.h>
|
| 33 |
+
#include <stdint.h>
|
| 34 |
+
#include <string.h>
|
| 35 |
+
#include <math.h>
|
| 36 |
+
#include <time.h>
|
| 37 |
+
#include <float.h>
|
| 38 |
+
|
| 39 |
+
#define BLOCK 256
|
| 40 |
+
#define MAX_DEG_A 6
|
| 41 |
+
#define MAX_DEG_B 12
|
| 42 |
+
#define MAX_CF_DEPTH 500
|
| 43 |
+
|
| 44 |
+
/* ── Known constants ──────────────────────────────────────── */
|
| 45 |
+
|
| 46 |
+
__constant__ double d_constants[] = {
|
| 47 |
+
3.14159265358979323846, // 0 pi
|
| 48 |
+
2.71828182845904523536, // 1 e
|
| 49 |
+
0.69314718055994530942, // 2 ln(2)
|
| 50 |
+
0.57721566490153286061, // 3 Euler-Mascheroni gamma
|
| 51 |
+
0.91596559417721901505, // 4 Catalan's constant
|
| 52 |
+
1.20205690315959428540, // 5 zeta(3)
|
| 53 |
+
1.03692775514336992633, // 6 zeta(5)
|
| 54 |
+
1.00834927738192282684, // 7 zeta(7)
|
| 55 |
+
0.83462684167407318628, // 8 Gauss's constant
|
| 56 |
+
2.62205755429211981046, // 9 Lemniscate constant
|
| 57 |
+
1.41421356237309504880, // 10 sqrt(2)
|
| 58 |
+
1.61803398874989484820, // 11 golden ratio phi
|
| 59 |
+
0.0,
|
| 60 |
+
};
|
| 61 |
+
|
| 62 |
+
static const char* h_const_names[] = {
|
| 63 |
+
"pi", "e", "ln(2)", "gamma", "Catalan",
|
| 64 |
+
"zeta(3)", "zeta(5)", "zeta(7)", "Gauss", "Lemniscate",
|
| 65 |
+
"sqrt(2)", "phi"
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
#define NUM_CONSTANTS 12
|
| 69 |
+
|
| 70 |
+
__constant__ double d_compounds[] = {
|
| 71 |
+
// Reciprocals
|
| 72 |
+
0.31830988618379067, // 1/pi
|
| 73 |
+
0.36787944117144233, // 1/e
|
| 74 |
+
1.44269504088896341, // 1/ln(2)
|
| 75 |
+
// Pi expressions
|
| 76 |
+
1.27323954473516269, // 4/pi
|
| 77 |
+
0.78539816339744831, // pi/4
|
| 78 |
+
1.57079632679489662, // pi/2
|
| 79 |
+
1.04719755119659775, // pi/3
|
| 80 |
+
0.52359877559829887, // pi/6
|
| 81 |
+
9.86960440108935862, // pi^2
|
| 82 |
+
1.64493406684822644, // pi^2/6 = zeta(2)
|
| 83 |
+
2.46740110027233966, // pi^2/4
|
| 84 |
+
0.82246703342411322, // pi^2/12
|
| 85 |
+
// Log expressions
|
| 86 |
+
1.38629436111989061, // 2*ln(2)
|
| 87 |
+
2.30258509299404568, // ln(10)
|
| 88 |
+
1.09861228866810970, // ln(3)
|
| 89 |
+
// Cross-products
|
| 90 |
+
8.53973422267356706, // e*pi
|
| 91 |
+
0.86525597943226508, // e/pi
|
| 92 |
+
1.15572734979092172, // pi/e
|
| 93 |
+
2.17758609030360229, // pi*ln(2)
|
| 94 |
+
// Roots
|
| 95 |
+
1.77245385090551603, // sqrt(pi)
|
| 96 |
+
0.56418958354775629, // 1/sqrt(pi)
|
| 97 |
+
1.12837916709551258, // 2/sqrt(pi)
|
| 98 |
+
2.50662827463100051, // sqrt(2*pi)
|
| 99 |
+
0.39894228040143268, // 1/sqrt(2*pi)
|
| 100 |
+
// Zeta products
|
| 101 |
+
3.77495308672748408, // pi*zeta(3)
|
| 102 |
+
0.0,
|
| 103 |
+
};
|
| 104 |
+
|
| 105 |
+
static const char* h_compound_names[] = {
|
| 106 |
+
"1/pi", "1/e", "1/ln(2)",
|
| 107 |
+
"4/pi", "pi/4", "pi/2", "pi/3", "pi/6",
|
| 108 |
+
"pi^2", "pi^2/6", "pi^2/4", "pi^2/12",
|
| 109 |
+
"2*ln(2)", "ln(10)", "ln(3)",
|
| 110 |
+
"e*pi", "e/pi", "pi/e", "pi*ln(2)",
|
| 111 |
+
"sqrt(pi)", "1/sqrt(pi)", "2/sqrt(pi)",
|
| 112 |
+
"sqrt(2pi)", "1/sqrt(2pi)",
|
| 113 |
+
"pi*zeta(3)",
|
| 114 |
+
};
|
| 115 |
+
|
| 116 |
+
#define NUM_COMPOUNDS 25
|
| 117 |
+
|
| 118 |
+
static const char* get_const_name(int mc) {
|
| 119 |
+
if (mc >= 100) return h_compound_names[mc - 100];
|
| 120 |
+
return h_const_names[mc];
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
/* ── Polynomial evaluation ────────────────────────────────── */
|
| 124 |
+
|
| 125 |
+
__device__ double eval_poly_a(const int *coeffs, int deg_a, int n) {
|
| 126 |
+
double result = 0.0, np = 1.0;
|
| 127 |
+
for (int i = 0; i <= deg_a; i++) {
|
| 128 |
+
result += coeffs[i] * np;
|
| 129 |
+
np *= (double)n;
|
| 130 |
+
}
|
| 131 |
+
return result;
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
__device__ double eval_poly_b(const int *coeffs, int deg_b, int n) {
|
| 135 |
+
double result = 0.0, np = 1.0;
|
| 136 |
+
for (int i = 0; i <= deg_b; i++) {
|
| 137 |
+
result += coeffs[i] * np;
|
| 138 |
+
np *= (double)n;
|
| 139 |
+
}
|
| 140 |
+
return result;
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
/* ── CF evaluation with asymmetric degrees ────────────────── */
|
| 144 |
+
|
| 145 |
+
__device__ double eval_pcf_asym(const int *a_coeffs, int deg_a,
|
| 146 |
+
const int *b_coeffs, int deg_b,
|
| 147 |
+
int depth)
|
| 148 |
+
{
|
| 149 |
+
// Backward recurrence: start from n=depth
|
| 150 |
+
double val = eval_poly_a(a_coeffs, deg_a, depth);
|
| 151 |
+
|
| 152 |
+
for (int n = depth - 1; n >= 1; n--) {
|
| 153 |
+
double bn1 = eval_poly_b(b_coeffs, deg_b, n + 1);
|
| 154 |
+
double an = eval_poly_a(a_coeffs, deg_a, n);
|
| 155 |
+
if (fabs(val) < 1e-300) return NAN;
|
| 156 |
+
val = an + bn1 / val;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
// CF = a(0) + b(1) / val
|
| 160 |
+
double a0 = eval_poly_a(a_coeffs, deg_a, 0);
|
| 161 |
+
double b1 = eval_poly_b(b_coeffs, deg_b, 1);
|
| 162 |
+
if (fabs(val) < 1e-300) return NAN;
|
| 163 |
+
return a0 + b1 / val;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
__device__ int check_convergence_asym(const int *a_coeffs, int deg_a,
|
| 167 |
+
const int *b_coeffs, int deg_b,
|
| 168 |
+
int depth, double *result)
|
| 169 |
+
{
|
| 170 |
+
double v1 = eval_pcf_asym(a_coeffs, deg_a, b_coeffs, deg_b, depth);
|
| 171 |
+
double v2 = eval_pcf_asym(a_coeffs, deg_a, b_coeffs, deg_b, depth - 50);
|
| 172 |
+
|
| 173 |
+
if (isnan(v1) || isnan(v2) || isinf(v1) || isinf(v2)) return 0;
|
| 174 |
+
if (fabs(v1) > 1e15 || fabs(v1) < 1e-15) return 0;
|
| 175 |
+
|
| 176 |
+
double reldiff = fabs(v1 - v2) / (fabs(v1) + 1e-300);
|
| 177 |
+
if (reldiff > 1e-10) return 0;
|
| 178 |
+
|
| 179 |
+
*result = v1;
|
| 180 |
+
return 1;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
/* ── Constant matching (same as v1 but with tighter threshold) ── */
|
| 184 |
+
|
| 185 |
+
__device__ int match_constant(double val, int *match_const, int *match_c0,
|
| 186 |
+
int *match_c1, int *match_c2)
|
| 187 |
+
{
|
| 188 |
+
double absval = val < 0.0 ? -val : val;
|
| 189 |
+
if (absval < 1e-8) return 0;
|
| 190 |
+
|
| 191 |
+
// Phase 1: compound expressions
|
| 192 |
+
for (int ci = 0; ci < NUM_COMPOUNDS; ci++) {
|
| 193 |
+
double K = d_compounds[ci];
|
| 194 |
+
if (K == 0.0) continue;
|
| 195 |
+
for (int c1 = 1; c1 <= 6; c1++) {
|
| 196 |
+
for (int c2 = -6; c2 <= 6; c2++) {
|
| 197 |
+
if (c2 == 0) continue;
|
| 198 |
+
for (int c0 = -6; c0 <= 6; c0++) {
|
| 199 |
+
double expected = ((double)c0 + (double)c2 * K) / (double)c1;
|
| 200 |
+
if (fabs(expected) < 1e-15 || fabs(expected) > 1e15) continue;
|
| 201 |
+
double reldiff = fabs(val - expected) / (fabs(expected) + 1e-300);
|
| 202 |
+
if (reldiff < 1e-11) {
|
| 203 |
+
*match_const = 100 + ci;
|
| 204 |
+
*match_c0 = c0; *match_c1 = c1; *match_c2 = c2;
|
| 205 |
+
return 1;
|
| 206 |
+
}
|
| 207 |
+
}
|
| 208 |
+
}
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
// Phase 2: base constants
|
| 213 |
+
for (int ci = 0; ci < NUM_CONSTANTS; ci++) {
|
| 214 |
+
double K = d_constants[ci];
|
| 215 |
+
if (K == 0.0) continue;
|
| 216 |
+
for (int c1 = 1; c1 <= 8; c1++) {
|
| 217 |
+
for (int c2 = -8; c2 <= 8; c2++) {
|
| 218 |
+
if (c2 == 0) continue;
|
| 219 |
+
for (int c0 = -8; c0 <= 8; c0++) {
|
| 220 |
+
double expected = ((double)c0 + (double)c2 * K) / (double)c1;
|
| 221 |
+
double reldiff = fabs(val - expected) / (fabs(expected) + 1e-300);
|
| 222 |
+
if (reldiff < 1e-12) {
|
| 223 |
+
*match_const = ci;
|
| 224 |
+
*match_c0 = c0; *match_c1 = c1; *match_c2 = c2;
|
| 225 |
+
return 1;
|
| 226 |
+
}
|
| 227 |
+
}
|
| 228 |
+
}
|
| 229 |
+
}
|
| 230 |
+
// Power matches
|
| 231 |
+
for (int p = -4; p <= 4; p++) {
|
| 232 |
+
for (int q = 1; q <= 4; q++) {
|
| 233 |
+
if (p == 0) continue;
|
| 234 |
+
double expected = pow(K, (double)p / (double)q);
|
| 235 |
+
if (isnan(expected) || isinf(expected)) continue;
|
| 236 |
+
double reldiff = fabs(val - expected) / (fabs(expected) + 1e-300);
|
| 237 |
+
if (reldiff < 1e-12) {
|
| 238 |
+
*match_const = ci;
|
| 239 |
+
*match_c0 = p; *match_c1 = q; *match_c2 = -999;
|
| 240 |
+
return 1;
|
| 241 |
+
}
|
| 242 |
+
}
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
return 0;
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
/* ── Main kernel ──────────────────────────────────────────── */
|
| 249 |
+
|
| 250 |
+
struct Hit {
|
| 251 |
+
int a_coeffs[MAX_DEG_A + 1];
|
| 252 |
+
int b_coeffs[MAX_DEG_B + 1];
|
| 253 |
+
int deg_a, deg_b;
|
| 254 |
+
double value;
|
| 255 |
+
int match_const;
|
| 256 |
+
int match_c0, match_c1, match_c2;
|
| 257 |
+
int matched; // 1 = matched a constant, 0 = converged but unmatched
|
| 258 |
+
};
|
| 259 |
+
|
| 260 |
+
__global__ void search_kernel(
|
| 261 |
+
long long start_idx, long long count,
|
| 262 |
+
int deg_a, int deg_b, int range_a, int range_b, int cf_depth,
|
| 263 |
+
Hit *hits, int *hit_count, int max_hits,
|
| 264 |
+
Hit *unmatched, int *unmatched_count, int max_unmatched)
|
| 265 |
+
{
|
| 266 |
+
long long tid = blockIdx.x * (long long)blockDim.x + threadIdx.x;
|
| 267 |
+
if (tid >= count) return;
|
| 268 |
+
|
| 269 |
+
long long idx = start_idx + tid;
|
| 270 |
+
|
| 271 |
+
// Decode: first (deg_a+1) coefficients for a, then (deg_b+1) for b
|
| 272 |
+
int width_a = 2 * range_a + 1;
|
| 273 |
+
int width_b = 2 * range_b + 1;
|
| 274 |
+
|
| 275 |
+
int a_coeffs[MAX_DEG_A + 1] = {0};
|
| 276 |
+
int b_coeffs[MAX_DEG_B + 1] = {0};
|
| 277 |
+
|
| 278 |
+
long long tmp = idx;
|
| 279 |
+
for (int i = 0; i <= deg_a; i++) {
|
| 280 |
+
a_coeffs[i] = (int)(tmp % width_a) - range_a;
|
| 281 |
+
tmp /= width_a;
|
| 282 |
+
}
|
| 283 |
+
for (int i = 0; i <= deg_b; i++) {
|
| 284 |
+
b_coeffs[i] = (int)(tmp % width_b) - range_b;
|
| 285 |
+
tmp /= width_b;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
// Skip trivial: b(n) = 0
|
| 289 |
+
int all_zero_b = 1;
|
| 290 |
+
for (int i = 0; i <= deg_b; i++) if (b_coeffs[i] != 0) { all_zero_b = 0; break; }
|
| 291 |
+
if (all_zero_b) return;
|
| 292 |
+
|
| 293 |
+
// Skip trivial: leading coefficient of b is zero (reduces to lower degree)
|
| 294 |
+
if (b_coeffs[deg_b] == 0) return;
|
| 295 |
+
|
| 296 |
+
// Evaluate CF
|
| 297 |
+
double value;
|
| 298 |
+
if (!check_convergence_asym(a_coeffs, deg_a, b_coeffs, deg_b, cf_depth, &value))
|
| 299 |
+
return;
|
| 300 |
+
|
| 301 |
+
// Skip trivial values
|
| 302 |
+
if (value == 0.0 || value != value || value > 1e15 || value < -1e15) return;
|
| 303 |
+
if (value > -1e-10 && value < 1e-10) return;
|
| 304 |
+
|
| 305 |
+
// Try matching
|
| 306 |
+
int mc, c0, c1, c2;
|
| 307 |
+
if (match_constant(value, &mc, &c0, &c1, &c2)) {
|
| 308 |
+
int slot = atomicAdd(hit_count, 1);
|
| 309 |
+
if (slot < max_hits) {
|
| 310 |
+
Hit *h = &hits[slot];
|
| 311 |
+
for (int i = 0; i <= deg_a; i++) h->a_coeffs[i] = a_coeffs[i];
|
| 312 |
+
for (int i = 0; i <= deg_b; i++) h->b_coeffs[i] = b_coeffs[i];
|
| 313 |
+
h->deg_a = deg_a; h->deg_b = deg_b;
|
| 314 |
+
h->value = value;
|
| 315 |
+
h->match_const = mc;
|
| 316 |
+
h->match_c0 = c0; h->match_c1 = c1; h->match_c2 = c2;
|
| 317 |
+
h->matched = 1;
|
| 318 |
+
}
|
| 319 |
+
} else {
|
| 320 |
+
// Save unmatched converged CFs for offline PSLQ
|
| 321 |
+
int slot = atomicAdd(unmatched_count, 1);
|
| 322 |
+
if (slot < max_unmatched) {
|
| 323 |
+
Hit *h = &unmatched[slot];
|
| 324 |
+
for (int i = 0; i <= deg_a; i++) h->a_coeffs[i] = a_coeffs[i];
|
| 325 |
+
for (int i = 0; i <= deg_b; i++) h->b_coeffs[i] = b_coeffs[i];
|
| 326 |
+
h->deg_a = deg_a; h->deg_b = deg_b;
|
| 327 |
+
h->value = value;
|
| 328 |
+
h->matched = 0;
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
}
|
| 332 |
+
|
| 333 |
+
/* ── Main ──────────────────────────────────────────────────── */
|
| 334 |
+
|
| 335 |
+
int main(int argc, char **argv) {
|
| 336 |
+
if (argc < 5) {
|
| 337 |
+
printf("Usage: %s <deg_a> <deg_b> <range_a> <range_b> [cf_depth] [gpu_id]\n", argv[0]);
|
| 338 |
+
printf("\nProductive configurations:\n");
|
| 339 |
+
printf(" %s 1 2 10 10 # Brouncker-type (194M candidates)\n", argv[0]);
|
| 340 |
+
printf(" %s 2 4 6 6 # Catalan-type (1.7T candidates)\n", argv[0]);
|
| 341 |
+
printf(" %s 3 6 3 3 # Apéry-type (282B candidates)\n", argv[0]);
|
| 342 |
+
printf(" %s 2 3 8 8 # mixed (4.7T candidates)\n", argv[0]);
|
| 343 |
+
return 1;
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
int deg_a = atoi(argv[1]);
|
| 347 |
+
int deg_b = atoi(argv[2]);
|
| 348 |
+
int range_a = atoi(argv[3]);
|
| 349 |
+
int range_b = atoi(argv[4]);
|
| 350 |
+
int cf_depth = argc > 5 ? atoi(argv[5]) : 300;
|
| 351 |
+
int gpu_id = argc > 6 ? atoi(argv[6]) : 0;
|
| 352 |
+
|
| 353 |
+
if (deg_a > MAX_DEG_A) { printf("ERROR: deg_a > %d\n", MAX_DEG_A); return 1; }
|
| 354 |
+
if (deg_b > MAX_DEG_B) { printf("ERROR: deg_b > %d\n", MAX_DEG_B); return 1; }
|
| 355 |
+
|
| 356 |
+
cudaSetDevice(gpu_id);
|
| 357 |
+
|
| 358 |
+
int width_a = 2 * range_a + 1;
|
| 359 |
+
int width_b = 2 * range_b + 1;
|
| 360 |
+
long long total_candidates = 1;
|
| 361 |
+
for (int i = 0; i <= deg_a; i++) total_candidates *= width_a;
|
| 362 |
+
for (int i = 0; i <= deg_b; i++) total_candidates *= width_b;
|
| 363 |
+
|
| 364 |
+
double ratio = (double)deg_b / (double)(deg_a > 0 ? deg_a : 1);
|
| 365 |
+
|
| 366 |
+
printf("========================================\n");
|
| 367 |
+
printf("Ramanujan Machine v2 (asymmetric degree)\n");
|
| 368 |
+
printf("========================================\n");
|
| 369 |
+
printf("a(n) degree: %d, coefficients: [-%d, %d]\n", deg_a, range_a, range_a);
|
| 370 |
+
printf("b(n) degree: %d, coefficients: [-%d, %d]\n", deg_b, range_b, range_b);
|
| 371 |
+
printf("Degree ratio: %.2f %s\n", ratio,
|
| 372 |
+
ratio >= 1.8 && ratio <= 2.2 ? "(OPTIMAL for transcendentals)" :
|
| 373 |
+
ratio >= 1.3 && ratio <= 1.7 ? "(sub-optimal but productive)" :
|
| 374 |
+
"(outside typical productive range)");
|
| 375 |
+
printf("CF evaluation depth: %d terms\n", cf_depth);
|
| 376 |
+
printf("Total candidates: %lld (%.2e)\n", total_candidates, (double)total_candidates);
|
| 377 |
+
printf("GPU: %d\n", gpu_id);
|
| 378 |
+
printf("========================================\n\n");
|
| 379 |
+
fflush(stdout);
|
| 380 |
+
|
| 381 |
+
// Allocate buffers
|
| 382 |
+
int max_hits = 500000;
|
| 383 |
+
int max_unmatched = 1000000; // save converged-but-unmatched for PSLQ
|
| 384 |
+
Hit *d_hits, *d_unmatched;
|
| 385 |
+
int *d_hit_count, *d_unmatched_count;
|
| 386 |
+
cudaMalloc(&d_hits, max_hits * sizeof(Hit));
|
| 387 |
+
cudaMalloc(&d_unmatched, max_unmatched * sizeof(Hit));
|
| 388 |
+
cudaMalloc(&d_hit_count, sizeof(int));
|
| 389 |
+
cudaMalloc(&d_unmatched_count, sizeof(int));
|
| 390 |
+
cudaMemset(d_hit_count, 0, sizeof(int));
|
| 391 |
+
cudaMemset(d_unmatched_count, 0, sizeof(int));
|
| 392 |
+
|
| 393 |
+
struct timespec t0, t1;
|
| 394 |
+
clock_gettime(CLOCK_MONOTONIC, &t0);
|
| 395 |
+
|
| 396 |
+
long long chunk_size = 1000000LL;
|
| 397 |
+
int total_hits = 0;
|
| 398 |
+
int total_unmatched = 0;
|
| 399 |
+
|
| 400 |
+
// Output files
|
| 401 |
+
char hits_path[512], unmatched_path[512];
|
| 402 |
+
snprintf(hits_path, 512,
|
| 403 |
+
"scripts/experiments/ramanujan-machine/results/v2_hits_a%d_b%d_r%d_%d.csv",
|
| 404 |
+
deg_a, deg_b, range_a, range_b);
|
| 405 |
+
snprintf(unmatched_path, 512,
|
| 406 |
+
"scripts/experiments/ramanujan-machine/results/v2_unmatched_a%d_b%d_r%d_%d.csv",
|
| 407 |
+
deg_a, deg_b, range_a, range_b);
|
| 408 |
+
|
| 409 |
+
FILE *fhits = fopen(hits_path, "w");
|
| 410 |
+
FILE *funm = fopen(unmatched_path, "w");
|
| 411 |
+
if (fhits) fprintf(fhits, "a_coeffs,b_coeffs,value,constant,c0,c1,c2\n");
|
| 412 |
+
if (funm) fprintf(funm, "a_coeffs,b_coeffs,value\n");
|
| 413 |
+
|
| 414 |
+
for (long long offset = 0; offset < total_candidates; offset += chunk_size) {
|
| 415 |
+
long long this_chunk = chunk_size;
|
| 416 |
+
if (offset + this_chunk > total_candidates)
|
| 417 |
+
this_chunk = total_candidates - offset;
|
| 418 |
+
|
| 419 |
+
int grid = (this_chunk + BLOCK - 1) / BLOCK;
|
| 420 |
+
search_kernel<<<grid, BLOCK>>>(
|
| 421 |
+
offset, this_chunk, deg_a, deg_b, range_a, range_b, cf_depth,
|
| 422 |
+
d_hits, d_hit_count, max_hits,
|
| 423 |
+
d_unmatched, d_unmatched_count, max_unmatched);
|
| 424 |
+
|
| 425 |
+
if ((offset / chunk_size) % 100 == 0 || offset + this_chunk >= total_candidates) {
|
| 426 |
+
cudaDeviceSynchronize();
|
| 427 |
+
|
| 428 |
+
int h_hit_count, h_unm_count;
|
| 429 |
+
cudaMemcpy(&h_hit_count, d_hit_count, sizeof(int), cudaMemcpyDeviceToHost);
|
| 430 |
+
cudaMemcpy(&h_unm_count, d_unmatched_count, sizeof(int), cudaMemcpyDeviceToHost);
|
| 431 |
+
|
| 432 |
+
// Write new matched hits
|
| 433 |
+
if (h_hit_count > total_hits) {
|
| 434 |
+
Hit *h_hits = (Hit *)malloc(h_hit_count * sizeof(Hit));
|
| 435 |
+
cudaMemcpy(h_hits, d_hits, h_hit_count * sizeof(Hit), cudaMemcpyDeviceToHost);
|
| 436 |
+
|
| 437 |
+
for (int i = total_hits; i < h_hit_count && i < max_hits; i++) {
|
| 438 |
+
Hit *h = &h_hits[i];
|
| 439 |
+
if (h->value > -1e-8 && h->value < 1e-8) continue;
|
| 440 |
+
|
| 441 |
+
printf(" HIT: a=(");
|
| 442 |
+
for (int j = 0; j <= h->deg_a; j++) printf("%s%d", j?",":"", h->a_coeffs[j]);
|
| 443 |
+
printf(") b=(");
|
| 444 |
+
for (int j = 0; j <= h->deg_b; j++) printf("%s%d", j?",":"", h->b_coeffs[j]);
|
| 445 |
+
printf(") → %.15g", h->value);
|
| 446 |
+
|
| 447 |
+
if (h->match_c2 == -999)
|
| 448 |
+
printf(" = %s^(%d/%d)", get_const_name(h->match_const),
|
| 449 |
+
h->match_c0, h->match_c1);
|
| 450 |
+
else
|
| 451 |
+
printf(" = (%d + %d*%s)/%d", h->match_c0, h->match_c2,
|
| 452 |
+
get_const_name(h->match_const), h->match_c1);
|
| 453 |
+
printf("\n");
|
| 454 |
+
|
| 455 |
+
if (fhits) {
|
| 456 |
+
fprintf(fhits, "\"(");
|
| 457 |
+
for (int j = 0; j <= h->deg_a; j++) fprintf(fhits, "%s%d", j?",":"", h->a_coeffs[j]);
|
| 458 |
+
fprintf(fhits, ")\",\"(");
|
| 459 |
+
for (int j = 0; j <= h->deg_b; j++) fprintf(fhits, "%s%d", j?",":"", h->b_coeffs[j]);
|
| 460 |
+
fprintf(fhits, ")\",%.*g,%s,%d,%d,%d\n",
|
| 461 |
+
17, h->value, get_const_name(h->match_const),
|
| 462 |
+
h->match_c0, h->match_c1, h->match_c2);
|
| 463 |
+
}
|
| 464 |
+
}
|
| 465 |
+
total_hits = h_hit_count;
|
| 466 |
+
free(h_hits);
|
| 467 |
+
if (fhits) fflush(fhits);
|
| 468 |
+
}
|
| 469 |
+
|
| 470 |
+
// Write new unmatched CFs
|
| 471 |
+
if (h_unm_count > total_unmatched) {
|
| 472 |
+
Hit *h_unm = (Hit *)malloc(h_unm_count * sizeof(Hit));
|
| 473 |
+
cudaMemcpy(h_unm, d_unmatched, h_unm_count * sizeof(Hit), cudaMemcpyDeviceToHost);
|
| 474 |
+
|
| 475 |
+
for (int i = total_unmatched; i < h_unm_count && i < max_unmatched; i++) {
|
| 476 |
+
Hit *h = &h_unm[i];
|
| 477 |
+
if (funm) {
|
| 478 |
+
fprintf(funm, "\"(");
|
| 479 |
+
for (int j = 0; j <= h->deg_a; j++) fprintf(funm, "%s%d", j?",":"", h->a_coeffs[j]);
|
| 480 |
+
fprintf(funm, ")\",\"(");
|
| 481 |
+
for (int j = 0; j <= h->deg_b; j++) fprintf(funm, "%s%d", j?",":"", h->b_coeffs[j]);
|
| 482 |
+
fprintf(funm, ")\",%.*g\n", 17, h->value);
|
| 483 |
+
}
|
| 484 |
+
}
|
| 485 |
+
total_unmatched = h_unm_count;
|
| 486 |
+
free(h_unm);
|
| 487 |
+
if (funm) fflush(funm);
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
clock_gettime(CLOCK_MONOTONIC, &t1);
|
| 491 |
+
double elapsed = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;
|
| 492 |
+
double pct = 100.0 * (offset + this_chunk) / total_candidates;
|
| 493 |
+
double rate = (offset + this_chunk) / elapsed;
|
| 494 |
+
double eta = (total_candidates - offset - this_chunk) / (rate + 1);
|
| 495 |
+
|
| 496 |
+
printf(" %.1f%% (%lld/%lld) %d matched, %d unmatched, %.0f/sec, ETA %.0fs\n",
|
| 497 |
+
pct, offset + this_chunk, total_candidates,
|
| 498 |
+
total_hits, total_unmatched, rate, eta);
|
| 499 |
+
fflush(stdout);
|
| 500 |
+
}
|
| 501 |
+
}
|
| 502 |
+
|
| 503 |
+
if (fhits) fclose(fhits);
|
| 504 |
+
if (funm) fclose(funm);
|
| 505 |
+
|
| 506 |
+
clock_gettime(CLOCK_MONOTONIC, &t1);
|
| 507 |
+
double total_time = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9;
|
| 508 |
+
|
| 509 |
+
printf("\n========================================\n");
|
| 510 |
+
printf("Ramanujan Machine v2 Results\n");
|
| 511 |
+
printf("========================================\n");
|
| 512 |
+
printf("a(n): deg=%d range=[-%d,%d]\n", deg_a, range_a, range_a);
|
| 513 |
+
printf("b(n): deg=%d range=[-%d,%d]\n", deg_b, range_b, range_b);
|
| 514 |
+
printf("Degree ratio: %.2f\n", ratio);
|
| 515 |
+
printf("Candidates: %lld (%.2e)\n", total_candidates, (double)total_candidates);
|
| 516 |
+
printf("Matched hits: %d\n", total_hits);
|
| 517 |
+
printf("Unmatched converged: %d (saved for PSLQ)\n", total_unmatched);
|
| 518 |
+
printf("Time: %.1fs (%.0f candidates/sec)\n", total_time,
|
| 519 |
+
total_candidates / total_time);
|
| 520 |
+
if (total_hits > 0)
|
| 521 |
+
printf("Hits CSV: %s\n", hits_path);
|
| 522 |
+
if (total_unmatched > 0)
|
| 523 |
+
printf("Unmatched CSV: %s\n", unmatched_path);
|
| 524 |
+
printf("========================================\n");
|
| 525 |
+
|
| 526 |
+
printf("\nNext step: run PSLQ verification on matched hits:\n");
|
| 527 |
+
printf(" python3 scripts/experiments/ramanujan-machine/verify_hits.py %s\n",
|
| 528 |
+
hits_path);
|
| 529 |
+
printf("Next step: run multi-constant PSLQ on unmatched CFs:\n");
|
| 530 |
+
printf(" python3 scripts/experiments/ramanujan-machine/pslq_scan.py %s\n",
|
| 531 |
+
unmatched_path);
|
| 532 |
+
|
| 533 |
+
cudaFree(d_hits); cudaFree(d_unmatched);
|
| 534 |
+
cudaFree(d_hit_count); cudaFree(d_unmatched_count);
|
| 535 |
+
return 0;
|
| 536 |
+
}
|
scripts/test.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""CPU-only verification test for Ramanujan Machine v2 (Asymmetric-Degree CF Search)"""
|
| 2 |
+
print("Testing ramanujan-machine-cuda...")
|
| 3 |
+
|
| 4 |
+
import math
|
| 5 |
+
|
| 6 |
+
def eval_cf(a_coeffs, b_coeffs, depth=100):
|
| 7 |
+
"""Evaluate generalized CF: a(0) + b(1)/(a(1) + b(2)/(a(2) + ...))"""
|
| 8 |
+
def a(n):
|
| 9 |
+
return sum(c * n**i for i, c in enumerate(a_coeffs))
|
| 10 |
+
def b(n):
|
| 11 |
+
return sum(c * n**i for i, c in enumerate(b_coeffs))
|
| 12 |
+
# Backward recurrence
|
| 13 |
+
val = a(depth)
|
| 14 |
+
for n in range(depth-1, 0, -1):
|
| 15 |
+
bn = b(n)
|
| 16 |
+
if abs(val) < 1e-15: break
|
| 17 |
+
val = a(n) + bn / val
|
| 18 |
+
return val
|
| 19 |
+
|
| 20 |
+
# Known: a(n)=2n+1, b(n)=-n^2 gives 4/pi - 1 (Brouncker-type)
|
| 21 |
+
# Actually: [1; 1,1,1,...] with a(n)=1,b(n)=1 = golden ratio
|
| 22 |
+
phi = (1 + math.sqrt(5)) / 2
|
| 23 |
+
val = eval_cf([1], [1])
|
| 24 |
+
print(f" CF [1;1,1,...] = {val:.10f} (phi = {phi:.10f})")
|
| 25 |
+
assert abs(val - phi) < 1e-6, f"Expected phi, got {val}"
|
| 26 |
+
|
| 27 |
+
# Known: a(n)=2n+1, b(n)=n^2 gives e-1 (Euler's CF for e)
|
| 28 |
+
# Actually e = 2 + 1/(1+1/(2+1/(1+1/(1+1/(4+...))))) but that's the regular CF
|
| 29 |
+
# Simpler: CF with a=[1,3,5,7,...], b=[0,1,1,1,...] for 4/pi? Let's just test golden ratio.
|
| 30 |
+
print(f"\n1/1 tests passed")
|
| 31 |
+
|
torch-ext/torch_binding.cpp
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <torch/extension.h>
|
| 2 |
+
#include "torch_binding.h"
|
| 3 |
+
|
| 4 |
+
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
| 5 |
+
m.doc() = "Ramanujan Machine v2 (Asymmetric-Degree CF Search) CUDA kernel";
|
| 6 |
+
}
|
torch-ext/torch_binding.h
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#pragma once
|
| 2 |
+
#include <torch/torch.h>
|
| 3 |
+
// See ramanujan/ramanujan_v2.cu for kernel API
|