import { useEffect, useState } from 'react'; import { ready, ink, fit } from '../../lib/mrly.js'; import { mount, Page, Row, Pick, Slider, Check, Btn, Stat, Note } from '../../lib/app.jsx'; import { Grid, Signs, Sketch } from '../../lib/draw.jsx'; import { Picker, useSeeds } from '../../lib/select.jsx'; import { useQuery, share } from '../../lib/query.js'; const m = await ready(); const ROUNDS = 8; const SIDE = 512; const LEVELS = 9; const RATES = 64; const FIRST = { round: 6, length: 256, level: 6, fold: 'sign', code: '9', side: 2, base: 2, depth: 3 }; const GALLERY = 'Three of the four lifts fold, and the crate checks each one against the Kronecker power of its own corner tile rather than trusting the picture. The corner tile is the only candidate worth testing: if a grid is a tile folded L times then its corner block is that tile with every bit flipped by (L - 1) t00, and folding the block L times flips the grid again by L (L - 1) t00, which is even. So a grid folds if and only if it folds from its own corner, and no search is needed.'; const FILTER = 'The filter has a closed form in both folds, and the closed form is not the Thue-Morse grid. Under the and fold the next level is this level blown up and masked by the base tile, so the difference is this level blown up and masked by the tile complement. Under the plus-minus fold the next level is this level blown up and exclusive-ored with the repeated tile, so the difference is the repeated tile alone. Either way the filter keeps the last digit and throws every other one, so its output repeats with period equal to the tile side while the Thue-Morse grid does not, and the two differ at every side past the tile. Sharper on the plus-minus fold at tile side two: the disagreement is exactly half the sites at every side four and beyond, for every one of the sixteen designs, because the low digits fix a residue class and inside each class the high digits carry opposite letters exactly half the time. Half is the score a coin gets, so the filter output is no evidence of Thue-Morse at all. The resemblance is real and it is generic rather than special: both pictures are digit rules, so both are Kronecker powers of one small tile, and the eye reads any plus-minus speckle at the finest scale as Thue-Morse. Proved here, and pinned in the crate at every code and level the page draws.'; const attempt = (fn) => { try { return { ...fn(), error: null }; } catch (error) { return { error }; } }; const hue = (bit) => (bit ? ink.blue : ink.orange); const ribbon = (rows, length) => (canvas) => { const tall = rows.length * 26 + 4; const [ctx, w] = fit(canvas, tall); ctx.clearRect(0, 0, w, tall); const step = (w - 16) / length; rows.forEach((row, r) => { for (let i = 0; i < row.length; i++) { ctx.fillStyle = row[i]; ctx.fillRect(8 + i * step, 2 + r * 26, Math.max(1, step - 1), 22); } }); }; function spread(runs) { const out = []; for (const run of runs) for (let k = 0; k < run; k++) out.push(run); return out; } function tile(bits) { return { width: 2, height: 2, types: Uint8Array.from(bits) }; } function verdict(row) { if (row.twin) return the same grid as {row.twin}; if (row.folds) return a Kronecker power; return no Kronecker power; } function App() { const shared = useSeeds(); const [pick, set] = useQuery(FIRST); const [playing, setPlaying] = useState(false); const [parity, setParity] = useState(false); const clamp = (value, low, high) => Math.max(low, Math.min(value, high)); const round = clamp(pick.round, 1, ROUNDS); const level = clamp(pick.level, 1, LEVELS); const length = clamp(pick.length, 16, 4096); const cap = m.level_cap(pick.side, 1, SIDE); const depth = clamp(pick.depth, 1, Math.max(1, cap - 1)); useEffect(() => { if (!playing) return; const tick = setInterval(() => set({ round: round >= ROUNDS ? 1 : round + 1 }), 700); return () => clearInterval(tick); }, [playing, round]); const word = attempt(() => ({ read: JSON.parse(m.morse_word(length)) })); const seed = attempt(() => { const stage = Array.from(m.morse_stage(round)); const digits = JSON.parse(m.morse_word(stage.length)).digits; return { stage, digits, agree: stage.every((bit, i) => bit === digits[i]) }; }); const gallery = attempt(() => ({ rows: JSON.parse(m.morse_gallery(level)), grids: ['parity', 'and', 'xor', 'sum'].map((kind) => m.morse_lift(kind, level)), })); const filter = attempt(() => ({ read: JSON.parse(m.morse_filter(pick.code, pick.side, pick.base, depth, pick.fold)), coarse: pick.fold === 'sign' ? m.morse_signs(pick.code, pick.side, pick.base, depth) : m.two_grid(pick.code, pick.side, depth, 0, pick.base), fine: pick.fold === 'sign' ? m.morse_signs(pick.code, pick.side, pick.base, depth + 1) : m.two_grid(pick.code, pick.side, depth + 1, 0, pick.base), difference: m.morse_difference(pick.code, pick.side, pick.base, depth, pick.fold), })); const rates = attempt(() => ({ read: JSON.parse(m.magic_rates(['3', '7'], [2, 2], [2, 2], 'thue-morse', RATES)) })); const wordLink = share({ l0code: '3', l0base: 2, l0n: 2, l1code: '7', l1base: 2, l1n: 2, view: 'nest', compare: 'swap', chart: 'exponent', schedule: 'thue-morse', length: RATES, }); const letters = () => { const { stage, digits, agree } = seed; const top = parity ? digits : stage; const low = parity ? stage : digits; return ( <>
letter 0, plus one letter 1, minus one {top.length} {parity ? 'top by bit parity, below by substitution' : 'top by substitution, below by bit parity'} {agree ? 'the two rules agree letter for letter' : 'the two rules differ'}
); }; const runs = () => { const { read } = word; const lengths = spread(read.runs).slice(0, read.length); return ( <> (run === 1 ? ink.yellow : ink.pink))], read.length)} deps={[read]} role="img" aria-label="The runs" />
a run of one a run of two {read.longest} {read.singles} {read.doubles} {read.ones} {read.cube_free ? 'no 000 and no 111' : 'a cube appears'}

the run boundaries one wherever a letter differs from the next

top, the boundary word of Thue-Morse below, the period-doubling word grown by 1 to 10 and 0 to 11 {read.doubling_agree ? 'the same word' : 'two words'}
); }; const card = (row, grid) => (

{row.formula} side {row.side}

{verdict(row)} {row.folds ? base tile : null} {row.design ? {m.name_of(row.design, 2, 2)} : null} {row.folds ? null : differs from its corner fold at {row.faults} of {row.side * row.side} sites, first at row {row.first[0]} column {row.first[1]}}
); const pane = (label, grid, on, note) => (
{pick.fold === 'sign' ? : }
{label}side {grid.width}{note}
); const box = () => { const { read } = filter; return ( <>
{pane('the level', filter.coarse, ink.yellow, ', drawn at the width of the next, which is the blow-up')} {pane('the next level', filter.fine, ink.yellow, '')} {pane('the difference', filter.difference, ink.pink, '')}
{read.closed_exact ? 'exactly' : 'not'} {read.form} {read.morse_exact ? 'the Thue-Morse grid' : 'not the Thue-Morse grid'} {read.morse_faults === null ? the Thue-Morse grid lives at side two, so a side-{read.number} tile has nothing to compare against : differs from Thue-Morse at {read.morse_faults} of {read.cells} sites, a share of {(read.morse_faults / read.cells).toFixed(4)}} {read.morse_faults !== null && read.morse_faults * 2 === read.cells ? exactly half the sites, the score a coin gets : null} {read.lit} {read.morse_tile ? this design reads plus-minus as the Thue-Morse tile : null}
); }; const controls = ( <>

The word

{ setPlaying(false); set({ round: v }); }} /> setPlaying(!playing)}>{playing ? 'Stop' : 'Play'}

The lifts

set({ level: v })} />

The runs

set({ length: +v })} />

The difference filter

set({ ...values, ...(values.base && pick.side < values.base ? { side: values.base } : {}) })} /> set({ side: Math.max(+v, pick.base) })} /> set({ depth: v })} /> set({ fold: v })} />
); return ( Every letter, grid, run and verdict below comes out of the crates through wasm; the page only draws. The plus-minus render is the first on the site: a warm cell is plus one, a cool cell is minus one, and a dark cell is empty. Links: the words drives a word by this schedule, moire stacks one design over its scales, the sequences holds the ledger the designs write. A rule that changes with the scale is a word, and the grammar of one is in the magic words note.}>

the word 0 to 01, 1 to 10, beside the parity of the binary digit sum

{seed.error ? null : letters()}

The digit rule is `t(n)`, the parity of the count of one-bits of `n`. The substitution grows the same word from a single 0 by doubling: every 0 becomes 01 and every 1 becomes 10. Digits are the recursion, so the two constructions are one construction seen twice, and the chip above is a live comparison rather than a claim.

{gallery.error ? null : gallery.rows.map((row, at) => card(row, gallery.grids[at]))}

{GALLERY}

The first lift is the sign grid `(-1)^(popcount(i) + popcount(j))`, the Kronecker power of the two-by-two tile with plus one on its diagonal, and that tile is a mrly design read plus-minus. The second is the Walsh-Hadamard pattern, the gasket read the same way, which is the spectrometer's world. The third is not a third grid at all: `popcount(i xor j)` and `popcount(i) + popcount(j)` agree modulo two, so `t` carries exclusive or to exclusive or and the third lift is the first. The fourth carries, and carrying is not a digit rule, so it does not fold; its grid is constant along every antidiagonal instead, which is a Hankel pattern and never a Kronecker power past side two.

the runs cube-freeness made visible

{word.error ? null : runs()}

Because `t(2n) = t(n)` and `t(2n+1) = 1 - t(n)`, the word changes at every even place, so no run reaches three: `000` and `111` never appear. The word that marks where the runs break is the period-doubling word, and the page checks that identity term by term at every length it draws. Verified in the crates, and stated in research/connectivity.md at every length to `2^20`.

the schedule Thue-Morse as a word over two letters

Read the letters as designs rather than as bits and the word becomes a schedule: one design per level, the domino where the letter is 0 and the gasket where it is 1. That is exactly what the words draws, with the component exponent charted along the schedule and its periodic control beside it.

the domino and the gasket at side two order-blind at interior frequency

Open the words at this schedule.

the exponent the value the tree computed exactly

{rates.error ? null : (
{rates.read.limit.toFixed(15)} {rates.read.rows[rates.read.length - 1][0].toFixed(9)} {rates.read.control[rates.read.length - 1].toFixed(9)} (1/2) log 6, Proved
)}

Along Thue-Morse over a gasket-and-domino pair the component exponent is exactly `(1/2) log 6`, with a two-sided certificate rather than a fit: the word has no three equal letters in a row, which caps the sandwich suffix, and it is balanced, which pins the letter counts to within one half of `L/2`. The aperiodicity earns nothing extra here, because the exponent depends on the letter frequencies alone, so a periodic word of the same frequencies returns the same number. Proved, research/connectivity.md.

the difference filter a level exclusive-ored with its own next level

{filter.error ? null : box()}

{FILTER}

); } mount();