Pick a set below and watch two things happen at once: the running sum of n1 over the set, and a live search for 3-term arithmetic progressions hiding inside it — triples a,a+d,a+2d all in the set.
<p class="hint">Every set below is a run of positive integers. Watch the running sum of reciprocals grow underneath it, and see which numbers (highlighted in red) belong to a 3-term arithmetic progression <b>a, a+d, a+2d</b> hiding inside the set.</p>
<div class="controls">
<label for="setPicker">Set:</label>
<select id="setPicker">
<option value="powers2">Powers of two (1, 2, 4, 8, …) — sum converges</option>
<option value="squares">Perfect squares (1, 4, 9, 16, …) — sum converges</option>
<option value="primes">Primes (2, 3, 5, 7, …) — sum diverges</option>
<option value="all" selected>All positive integers — sum diverges</option>
</select>
<button id="search" type="button">Search for progressions</button>
</div>
<div class="sumline" id="sumline">Pick a set to see its reciprocal sum.</div>
<div id="track" class="track"></div>
<div class="status" id="status">Click search to hunt for arithmetic progressions.</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.controls { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; margin-bottom: .6rem; }
.controls label { font-size: .85rem; font-weight: 600; color: #1d3557; }
select { font: 600 14px system-ui, sans-serif; padding: .4rem .6rem; border-radius: 8px; border: 1px solid #adb1b8; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
.sumline { font: 700 15px ui-monospace, monospace; color: #1d3557; margin: .3rem 0 .5rem; }
.track { display: flex; flex-wrap: wrap; gap: 6px; margin: .4rem 0; min-height: 46px; }
.num { width: 40px; height: 34px; display: flex; align-items: center; justify-content: center;
font: 700 13px ui-monospace, monospace; border-radius: 6px; background: #e8eef3;
color: #1d3557; border: 1px solid #cdd9e3; transition: all .15s; }
.num.ap { background: #e63946; border-color: #c92f3c; color: #fff; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.diverge { color: #0a7d33; }
.status.converge { color: #c92f3c; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Four example sets — two with a convergent reciprocal sum, two with a divergent one.
const SETS = {
// Sparse: reciprocals sum to < 2 no matter how far you extend it.
powers2: [1,2,4,8,16,32,64,128,256,512],
// Also sparse enough to converge (sum of 1/n^2 = pi^2/6 in the limit).
squares: Array.from({length:12}, (_,i)=>(i+1)*(i+1)),
// The sum of reciprocals of primes diverges (Euler, 1737), despite primes thinning out.
primes: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71],
// The harmonic series 1 + 1/2 + 1/3 + ... diverges, famously slowly.
all: Array.from({length:40}, (_,i)=>i+1),
};
// Whether each set's reciprocal sum diverges, for the status message.
const DIVERGES = { powers2: false, squares: false, primes: true, all: true };
let current = 'all';
// Brute-force scan: for every pair a < b in the set, check whether a + 2(b-a) is also in the set.
function findAPs(arr){
const set = new Set(arr);
const sorted = [...arr].sort((a,b)=>a-b);
const found = [];
for (let i=0;i<sorted.length;i++){
for (let j=i+1;j<sorted.length;j++){
const a = sorted[i], b = sorted[j], d = b-a;
if (d<=0) continue;
const c = b+d;
if (set.has(c)) found.push([a,b,c]);
}
}
return found;
}
function render(){
const arr = SETS[current];
const track = document.getElementById('track');
track.innerHTML = '';
let sum = 0;
const sums = arr.map(n => { sum += 1/n; return sum; });
const aps = findAPs(arr);
const inAP = new Set();
aps.forEach(([a,b,c]) => { inAP.add(a); inAP.add(b); inAP.add(c); });
arr.forEach((n, idx) => {
const d = document.createElement('div');
d.className = 'num' + (inAP.has(n) ? ' ap' : '');
d.textContent = n;
d.title = i18nFmt('running sum so far: %s%', { s: sums[idx].toFixed(3) });
track.appendChild(d);
});
const finalSum = sums[sums.length-1];
document.getElementById('sumline').textContent =
i18nFmt('Sum of 1/n over this set so far: %s%', { s: finalSum.toFixed(3) });
setStatus(aps.length, DIVERGES[current]);
}
function setStatus(count, diverges){
const s = document.getElementById('status');
if (diverges) {
s.textContent = i18nFmt('Reciprocals diverge — and sure enough, %n% number(s) sit inside a 3-term arithmetic progression.', { n: count });
s.className = 'status diverge';
} else {
s.textContent = i18nFmt('Reciprocals converge — this set is nearly starved of arithmetic progressions (%n% number(s) involved).', { n: count });
s.className = 'status converge';
}
}
document.getElementById('setPicker').addEventListener('change', (e) => {
current = e.target.value;
render();
});
document.getElementById('search').addEventListener('click', render);
render();
<p class="hint">Every set below is a run of positive integers. Watch the running sum of reciprocals grow underneath it, and see which numbers (highlighted in red) belong to a 3-term arithmetic progression <b>a, a+d, a+2d</b> hiding inside the set.</p>
<div class="controls">
<label for="setPicker">Set:</label>
<select id="setPicker">
<option value="powers2">Powers of two (1, 2, 4, 8, …) — sum converges</option>
<option value="squares">Perfect squares (1, 4, 9, 16, …) — sum converges</option>
<option value="primes">Primes (2, 3, 5, 7, …) — sum diverges</option>
<option value="all" selected>All positive integers — sum diverges</option>
</select>
<button id="search" type="button">Search for progressions</button>
</div>
<div class="sumline" id="sumline">Pick a set to see its reciprocal sum.</div>
<div id="track" class="track"></div>
<div class="status" id="status">Click search to hunt for arithmetic progressions.</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.controls { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; margin-bottom: .6rem; }
.controls label { font-size: .85rem; font-weight: 600; color: #1d3557; }
select { font: 600 14px system-ui, sans-serif; padding: .4rem .6rem; border-radius: 8px; border: 1px solid #adb1b8; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
.sumline { font: 700 15px ui-monospace, monospace; color: #1d3557; margin: .3rem 0 .5rem; }
.track { display: flex; flex-wrap: wrap; gap: 6px; margin: .4rem 0; min-height: 46px; }
.num { width: 40px; height: 34px; display: flex; align-items: center; justify-content: center;
font: 700 13px ui-monospace, monospace; border-radius: 6px; background: #e8eef3;
color: #1d3557; border: 1px solid #cdd9e3; transition: all .15s; }
.num.ap { background: #e63946; border-color: #c92f3c; color: #fff; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.diverge { color: #0a7d33; }
.status.converge { color: #c92f3c; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Four example sets — two with a convergent reciprocal sum, two with a divergent one.
const SETS = {
// Sparse: reciprocals sum to < 2 no matter how far you extend it.
powers2: [1,2,4,8,16,32,64,128,256,512],
// Also sparse enough to converge (sum of 1/n^2 = pi^2/6 in the limit).
squares: Array.from({length:12}, (_,i)=>(i+1)*(i+1)),
// The sum of reciprocals of primes diverges (Euler, 1737), despite primes thinning out.
primes: [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71],
// The harmonic series 1 + 1/2 + 1/3 + ... diverges, famously slowly.
all: Array.from({length:40}, (_,i)=>i+1),
};
// Whether each set's reciprocal sum diverges, for the status message.
const DIVERGES = { powers2: false, squares: false, primes: true, all: true };
let current = 'all';
// Brute-force scan: for every pair a < b in the set, check whether a + 2(b-a) is also in the set.
function findAPs(arr){
const set = new Set(arr);
const sorted = [...arr].sort((a,b)=>a-b);
const found = [];
for (let i=0;i<sorted.length;i++){
for (let j=i+1;j<sorted.length;j++){
const a = sorted[i], b = sorted[j], d = b-a;
if (d<=0) continue;
const c = b+d;
if (set.has(c)) found.push([a,b,c]);
}
}
return found;
}
function render(){
const arr = SETS[current];
const track = document.getElementById('track');
track.innerHTML = '';
let sum = 0;
const sums = arr.map(n => { sum += 1/n; return sum; });
const aps = findAPs(arr);
const inAP = new Set();
aps.forEach(([a,b,c]) => { inAP.add(a); inAP.add(b); inAP.add(c); });
arr.forEach((n, idx) => {
const d = document.createElement('div');
d.className = 'num' + (inAP.has(n) ? ' ap' : '');
d.textContent = n;
d.title = i18nFmt('running sum so far: %s%', { s: sums[idx].toFixed(3) });
track.appendChild(d);
});
const finalSum = sums[sums.length-1];
document.getElementById('sumline').textContent =
i18nFmt('Sum of 1/n over this set so far: %s%', { s: finalSum.toFixed(3) });
setStatus(aps.length, DIVERGES[current]);
}
function setStatus(count, diverges){
const s = document.getElementById('status');
if (diverges) {
s.textContent = i18nFmt('Reciprocals diverge — and sure enough, %n% number(s) sit inside a 3-term arithmetic progression.', { n: count });
s.className = 'status diverge';
} else {
s.textContent = i18nFmt('Reciprocals converge — this set is nearly starved of arithmetic progressions (%n% number(s) involved).', { n: count });
s.className = 'status converge';
}
}
document.getElementById('setPicker').addEventListener('change', (e) => {
current = e.target.value;
render();
});
document.getElementById('search').addEventListener('click', render);
render();
Notice the pattern. A sparse set like the powers of two (1,2,4,8,16,…) has a reciprocal sum that converges — and it turns out to have essentially no 3-term progressions at all. A dense set like all positive integers, or the primes, has a divergent sum — and progressions turn up everywhere, almost immediately.
Comments
Loading comments...