User:ArrowHead294/Purely consistent EDOs by odd limit/Appendix: Difference between revisions
ArrowHead294 (talk | contribs) m No need for separate page for now Tag: Blanking |
ArrowHead294 (talk | contribs) mNo edit summary |
||
| (12 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
== Additional results == | |||
The smallest EDOs purely consistent in the 7-, 15-, 31-, and 63-odd-limits are 10, 87, 311, and 3159811, respectively. | |||
Additionally, there are (12) 7-odd-limit purely-consistent EDOs less than 87, (3) 15-odd-limit purely-consistent EDOs less than 311, and (481) 31-odd-limit purely consistent EDOs less than 3159811. | |||
<div style="margin-bottom: 1em;"> | |||
{{Databox | |||
| 7-odd-limit purely-consistent EDOs less than 87 | |||
| {{normal|{{EDOs| 10, 15, 22, 31, 41, 46, 53, 56, 68, 72, 77, 84 }}}} | |||
}} | |||
</div><div style="margin-bottom: 1em;"> | |||
{{Databox | |||
| 15-odd-limit purely-consistent EDOs less than 311 | |||
| {{normal|{{EDOs| 87, 224, 270 }}}} | |||
}} | |||
</div><div style="margin-bottom: 1em;"> | |||
{{Databox | |||
| 31-odd-limit purely consistent EDOs less than 3159811 | |||
| {{normal|{{EDOs| 311, 16808, 20567, 25540, 28342, 31920, 34691, 60392, 65322, 90623, 93664, 116498, 124702, 143958, 148418, 164838, 165226, 165879, 175878, 185793, 195339, 195727, 209851, 210569, 212147, 220633, 241200, 248975, 256119, 263323, 265323, 266901, 285172, 286350, 292376, 298467, 301592, 308712, 318400, 324296, 328645, 330645, 334553, 339998, 344145, 346742, 349643, 351672, 354185, 358987, 360565, 363466, 370499, 371564, 373677, 377373, 385729, 385912, 389618, 395256, 405050, 406296, 406426, 414965, 431385, 439524, 451051, 459944, 460438, 470372, 477470, 482971, 490175, 490358, 491510, 494589, 530634, 536089, 536443, 536983, 542792, 547442, 550955, 570416, 571134, 579803, 587942, 589737, 590843, 597876, 606545, 607263, 610304, 610776, 612764, 642696, 643349, 646915, 649428, 652630, 666236, 669749, 675269, 684507, 687632, 710208, 729980, 732129, 736360, 739261, 739914, 744899, 746294, 751267, 753168, 763102, 763820, 766861, 771834, 775347, 775530, 785464, 791767, 824588, 829142, 836917, 839818, 849034, 850740, 852075, 855154, 859279, 861279, 866153, 876087, 891199, 896654, 905140, 911520, 920777, 922172, 934600, 937585, 948507, 948724, 951408, 958441, 965315, 965532, 971341, 977560, 986099, 1002907, 1003914, 1007697, 1024505, 1025223, 1030314, 1035157, 1041313, 1042031, 1044761, 1045072, 1051965, 1055543, 1078300, 1090545, 1095937, 1096925, 1099826, 1100479, 1109760, 1110083, 1117287, 1118576, 1122272, 1124385, 1132206, 1132399, 1141410, 1144451, 1146747, 1149207, 1152332, 1161259, 1161977, 1163331, 1173330, 1177679, 1183575, 1183898, 1200383, 1206732, 1220950, 1235074, 1236652, 1238652, 1248586, 1251882, 1265705, 1272803, 1281342, 1298150, 1306164, 1311973, 1326097, 1330723, 1334236, 1336031, 1336749, 1337137, 1349124, 1359058, 1359776, 1363472, 1371247, 1373406, 1385788, 1395722, 1402459, 1403748, 1405326, 1410952, 1412530, 1418879, 1430801, 1432379, 1441583, 1447221, 1456502, 1461044, 1464029, 1476274, 1477852, 1479141, 1501975, 1506905, 1507476, 1508194, 1510114, 1511909, 1521824, 1522542, 1536666, 1539350, 1542475, 1549284, 1553474, 1567297, 1577231, 1581515, 1594757, 1595639, 1598323, 1601448, 1612447, 1615348, 1626270, 1626795, 1660650, 1662269, 1667854, 1680894, 1691893, 1696307, 1697702, 1705229, 1711826, 1712544, 1714510, 1719623, 1726755, 1737149, 1749201, 1756675, 1771517, 1777866, 1785865, 1788325, 1791366, 1800753, 1810687, 1823016, 1824594, 1829312, 1833714, 1836528, 1836839, 1846120, 1853647, 1862540, 1867470, 1872474, 1887704, 1894106, 1895501, 1897231, 1908401, 1912309, 1918335, 1921159, 1953026, 1955322, 1959105, 1973012, 1975913, 1976631, 1984052, 2010604, 2026347, 2027412, 2027636, 2038064, 2044444, 2051887, 2052458, 2066011, 2073109, 2083614, 2086792, 2089917, 2092818, 2092958, 2095859, 2097931, 2109766, 2112279, 2114739, 2116970, 2126090, 2129087, 2132082, 2148890, 2151791, 2161135, 2169674, 2183581, 2186482, 2197404, 2202225, 2203290, 2207338, 2208403, 2222568, 2222751, 2224146, 2235863, 2268836, 2285644, 2287439, 2293658, 2296255, 2299768, 2307242, 2310466, 2313591, 2322655, 2327809, 2331117, 2355228, 2358741, 2372564, 2381821, 2382209, 2384281, 2387794, 2390090, 2396333, 2398629, 2427682, 2442601, 2448969, 2458496, 2461481, 2463951, 2475304, 2479535, 2488074, 2489652, 2504882, 2515127, 2526480, 2534619, 2543158, 2547047, 2556981, 2563855, 2570888, 2581738, 2595250, 2598546, 2599941, 2609328, 2619262, 2622303, 2626006, 2639829, 2640400, 2646426, 2651182, 2654223, 2663952, 2671031, 2676657, 2680900, 2685873, 2687839, 2688774, 2691005, 2702681, 2712926, 2719306, 2722207, 2722925, 2733182, 2739733, 2742774, 2753857, 2756898, 2757616, 2773706, 2774424, 2775819, 2784358, 2784488, 2787936, 2788247, 2793885, 2798181, 2809534, 2810693, 2814989, 2833397, 2839112, 2841541, 2861033, 2861751, 2881600, 2893789, 2895184, 2903723, 2904434, 2924420, 2932776, 2934354, 2940657, 2949196, 2949584, 2963407, 2969045, 2971946, 2972223, 2978249, 2981504, 2982157, 2986571, 2997710, 2999676, 3000394, 3008169, 3014906, 3037222, 3044366, 3046826, 3049339, 3051893, 3056760, 3068949, 3076392, 3083490, 3100298, 3103069, 3114422, 3128115, 3134271, 3134989, 3139285, 3144923, 3148812, 3151797, 3158746 }}}} | |||
}} | |||
</div> | |||
== Code used == | |||
This is the {{w|JavaScript}} code I use to find purely-consistent EDOs by odd limit. | |||
=== Original === | |||
<syntaxhighlight lang="javascript"> | |||
function et_error(interval, et) | |||
{ | |||
return [1200, et * 100].map(x => Math.round(x * 100 * (Math.round(et * Math.log2(interval)) / et - Math.log2(interval))) / 100).concat(Math.round(et * Math.log2(interval)) % et); | |||
} | |||
function min_et(h, max_err_pct, max_edos) | |||
{ | |||
var a = 0, i = 1, j = 0, start = Date.now(), output = new Array(); | |||
h = Math.round(Math.abs(h)); | |||
h = h + 1 - (h % 2); | |||
while (j <= max_edos) | |||
{ | |||
a = 1; | |||
for (var k = 3; k <= h; k += 2) | |||
{ | |||
if (Math.abs(et_error(k, i)[1]) > max_err_pct) | |||
{ | |||
a = 0; | |||
} | |||
} | |||
if (a == 1) | |||
{ | |||
j++; | |||
console.log(i + " | " + (Date.now() - start)/1000 + "s"); | |||
} | |||
i++; | |||
} | |||
} | |||
</syntaxhighlight> | |||
=== Current === | |||
(Note: This code was written with the assistance of Claude Opus 5, an artificial intelligence tool.) | |||
<syntaxhighlight lang="javascript"> | |||
/** | |||
* Generates a list of equal divisions of the octave that approximate the harmonic series well. | |||
* | |||
* An EDO qualifies when every odd harmonic from 3 to `h` falls within `thresh` of one of its steps, measured as a fraction of | |||
* a step. Even harmonics are skipped: they are octave transpositions of odd ones, and the octave is exact in any EDO. | |||
* | |||
* Searches upward without an upper bound, logging each hit with the elapsed time, and returns once `max_edos` have been | |||
* found. Qualifying EDOs always exist, but they thin out fast, so high `h` can take a very long time to find. | |||
* | |||
* @param {Number} h - Highest harmonic to check. Internally this value is rounded up to the current or next highest odd | |||
* number. This means inputting 32 and 33 will both check through 33. Anything below 3 accepts every EDO. | |||
* Usually this is set to one less than a power of two (e.g. 7, 15, 31, or 63) | |||
* @param {Number} max_edos - How many EDOs to find before stopping. | |||
* @param {Number} [start=1] - Lowest EDO to consider; "1 equal division of the octave" is simply whole-octave steps. | |||
* @param {Number} [thresh=0.25] - Tolerance as a fraction of a step. Defaults to 0.25 | |||
* @returns {Number[]} - The list of EDOs found, in ascending order. | |||
*/ | |||
function min_et(h, max_edos, start = 1, thresh = 0.25) | |||
{ | |||
h = Math.round(Math.abs(h)); | |||
h = h + 1 - (h % 2); | |||
start = Math.max(1, Math.round(start)); | |||
// Odd primes <=h | |||
let comp = new Int16Array(h + 1), primes = []; | |||
for (let p = 3; p <= h; p += 2) | |||
{ | |||
if (comp[p]) | |||
{ | |||
continue; | |||
} | |||
primes.push(p); | |||
for (let q = p * p; q <= h; q += 2 * p) | |||
{ | |||
comp[q] = 1; | |||
} | |||
} | |||
let m = primes.length, out = []; | |||
if (m === 0) | |||
{ | |||
for (let n = start; out.length < max_edos; n++) | |||
{ | |||
out.push(n); | |||
} | |||
return out; | |||
} | |||
// Per-prime tolerance: p, p^2, p^3, ... p^t collapse to |e_p| < thresh/t | |||
let logs = new Float64Array(m), tol = new Float64Array(m); | |||
for (let i = 0; i < m; i++) | |||
{ | |||
logs[i] = Math.log2(primes[i]); | |||
let t = 0; | |||
for (let q = primes[i]; q <= h; q *= primes[i]) | |||
{ | |||
t++; | |||
} | |||
tol[i] = thresh / t; | |||
} | |||
// Composites with >= 2 distinct factors, bucketed by largest factor | |||
let mixed = Array.from({length: m}, () => []); | |||
for (let k = 9; k <= h; k += 2) | |||
{ | |||
let n = k, top = -1, d = 0; | |||
let term = []; | |||
for (let i = 0; i < m && n > 1; i++) | |||
{ | |||
let p = primes[i]; | |||
if (n % p) | |||
{ | |||
continue; | |||
} | |||
let e = 0; | |||
while (n % p === 0) | |||
{ | |||
n /= p; | |||
e++; | |||
} | |||
term.push(i, e); | |||
top = i; | |||
d++; | |||
} | |||
if (d >= 2) | |||
{ | |||
mixed[top].push(Int32Array.from(term)); | |||
} | |||
} | |||
// 3-gap data for the 3-limit filter | |||
let err = new Float64Array(m); | |||
let a = logs[0], b = tol[0], L = 2 * b; // Target arc has length L | |||
let jm = 0, dm = 0, jn = 0, dn = 0; | |||
for (let j = 1; ; j++) | |||
{ | |||
let t = j * a; | |||
t -= Math.floor(t); | |||
if (!jm && t < L) | |||
{ | |||
jm = j; dm = t; | |||
} | |||
if (!jn && t > 1 - L) | |||
{ | |||
jn = j; dn = 1 - t; | |||
} | |||
if (jm && jn) | |||
{ | |||
break; | |||
} | |||
} | |||
let jmn = jm + jn, dmn = dm - dn, lim = L - dm; | |||
let N = start, x = start * a + b; x -= Math.floor(x); | |||
while (x >= L) | |||
{ | |||
N++; | |||
x += a - 1; | |||
if (x >= 1) | |||
{ | |||
x -= 1; | |||
} | |||
} | |||
// Search | |||
let t0 = Date.now(); | |||
let steps = 0; | |||
while (out.length < max_edos) | |||
{ | |||
err[0] = x - b; | |||
let ok = true; | |||
for (let i = 1; i < m; i++) | |||
{ | |||
let y = N * logs[i], e = y - Math.round(y); | |||
if (e >= tol[i] || e <= -tol[i]) | |||
{ | |||
ok = false; | |||
break; | |||
} | |||
err[i] = e; | |||
let g = mixed[i]; | |||
for (let t = 0; t < g.length; t++) | |||
{ | |||
let term = g[t]; | |||
let s = 0; | |||
for (let q = 0; q < term.length; q += 2) | |||
{ | |||
s += term[q + 1] * err[term[q]]; | |||
} | |||
s -= Math.round(s); | |||
if (s >= thresh || s <= -thresh) | |||
{ | |||
ok = false; | |||
break; | |||
} | |||
} | |||
if (!ok) | |||
{ | |||
break; | |||
} | |||
} | |||
if (ok) | |||
{ | |||
out.push(N); | |||
console.log(N + " | " + (Date.now() - t0) / 1000 + "s"); | |||
} | |||
// Jump to the next N that passes the 3-limit test | |||
if (x < lim) | |||
{ | |||
N += jm; | |||
x += dm; | |||
} | |||
else if (x >= dn) | |||
{ | |||
N += jn; | |||
x -= dn; | |||
} | |||
else | |||
{ | |||
N += jmn; x += dmn; | |||
} | |||
if ((++steps & 0xFFFFF) === 0) | |||
{ | |||
x = N * a + b; | |||
x -= Math.floor(x); | |||
} | |||
} | |||
return out; | |||
} | |||
</syntaxhighlight> | |||