Annus Mirabilis · Interactive critical edition in preparation
Random steps to diffusion
Add many independent steps and see a spread appear.
The independent-step argument
From random steps to diffusion
A coin gives only two possible next steps; a uniform law fills an interval; a Gaussian law has tails. Keep their step variance equal, and ask what survives after many independent steps.
Predict before the numbers
After many steps, what will changing the step law while keeping its variance do?
The result appears when you choose, say you have one in mind, or skip.
Observation buttons use the accepted setup, not unsubmitted draft edits. They return to the same trial, not a fresh sample.
Keeping a seed across step-law changes is a reproducible comparison, not a claim of independent trials. Shared links load settings only; they never start a calculation.
| Quantity | Accepted value |
|---|---|
| Step variance (μm²) | 0.25 |
| Step fourth moment (μm⁴) | 0.0625 |
| Diffusion coefficient (μm²/s) | 1.25 |
| Sample signed mean (μm) | 0.0005 |
| Sample mean square (μm²) | 0.9865 |
| Model mean square (μm²) | 1 |
| Model RMS displacement (μm) | 1 |
Static worked example
Model note
- Mean step (
stepMean), Step variance (stepSecondMoment), Step fourth moment (stepFourthMoment) and Mean step of the biased walk (biasedMean): Host calculation, by the site's own reference code. Computed indiffusion.kernelMoments. - Diffusion coefficient (
diffusionCoefficient), Diffusion coefficient of the biased walk, by the pure-diffusion argument (biasedDiffusion), Drift speed of the biased walk (biasedDrift), Centered-variance coefficient of the biased walk (biasedCenteredDiffusion) and Diffusion coefficient for Cauchy steps (cauchyDiffusion): Host calculation, by the site's own reference code. Computed indiffusion.kernelDiffusivity. - Excess kurtosis of one step (
stepKurtosis), Number of walkers (walkerCount), Excess kurtosis of the summed displacement (sumKurtosis), Shape plus sampling allowance (agreementBound), Whether the sample-to-Gaussian gap lies within the allowance (withinBound), Edges of the histogram bins (histogramEdges), Finite-step probability of each histogram bin (histogramExact), Times along the drawn traces (traceTimes), Step counts compared (comparisonSteps), Sample mean square at each compared step count (comparisonSampleMsd), Model mean square at each compared step count (comparisonModelMsd), Sample-to-Gaussian gap at each compared step count (comparisonDistance), Finite-step shape gap at each compared step count (comparisonShape), Intervals in the shrinking-interval table (continuumIntervals), Step RMS that keeps the ratio fixed, at each interval (fixedRatioSteps), Random draws executed for this request (requestDraws), Whether the existing recording was reused (reusedRecording) and Memory held by the kept recording, in bytes (retainedBytes): Host calculation, by the site's own reference code. Computed inbm05.measure. - Sample signed mean (
sampleMean), Sample mean square (sampleMeanSquare) and Sample coordinate RMS (sampleRms): Host calculation, by the site's own reference code. Computed indiffusion.ensembleMoments. - Model mean square (
modelMeanSquare), Model RMS displacement (modelRms) and Elapsed time (elapsedTime): Host calculation, by the site's own reference code. Computed indiffusion.randomWalkMoments. - Sampling allowance (
samplingTerm): Host calculation, by the site's own reference code. Computed indiffusion.dkwBound. - Walker positions after the last step (
walkPositions), Displacements along the drawn traces (traceDisplacements) and Random draws in the recording (recordingDraws): Host calculation, by the site's own reference code. Computed indiffusion.recordWalks. - Kolmogorov distance (
kolmogorovDistance): Host calculation, by the site's own reference code. Computed indiffusion.kolmogorovDistanceToGaussian. - Finite-step shape gap (
shapeTerm): Host calculation, by the site's own reference code. Computed indiffusion.kolmogorovShapeTerm. - Count in each histogram bin (
histogramCounts), Share of the sample in each histogram bin (histogramFrequencies), Samples below the plotted range (underflow) and Samples above the plotted range (overflow): Host calculation, by the site's own reference code. Computed indiffusion.displacementHistogram. - Gaussian probability of each histogram bin (
histogramGaussian): Host calculation, by the site's own reference code. Computed indiffusion.intervalProbability. - Displacements the coin walk can reach (
coinPositions), Exact probability of each coin-walk displacement (coinProbabilities), Coin paths ending at each displacement (coinNumerators) and Number of equally likely coin paths (coinDenominator): Host calculation, by the site's own reference code. Computed indiffusion.coinWalkDistribution. - Diffusion coefficient as the interval shrinks with the step fixed (
continuumLimit), Coefficient with the step kept fixed, at each interval (fixedStepCoefficients) and Coefficient with the ratio kept fixed, at each interval (fixedRatioCoefficients): Host calculation, by the site's own reference code. Computed indiffusion.continuumLimit. - Random draws replayed from the recording (
replayedDraws): Host calculation, by the site's own reference code. Computed indiffusion.observeWalks. - Seed 1905: with the same settings, the same seed replays the same trial.
- Computed from the settings last applied (settings revision 1, result 1).
- Not modeled: A continuous Langevin path; only independent steps of a chosen law.
- Show the code
Accepted Equal left/right jumps: 2000 walkers after 4 steps, model mean square 1 square micrometres.
Accepted trial: Equal left/right jumps; seed 1905; 2000 walkers; step RMS 0.5 μm; interval 0.1 s. Observed after 4 of 400 recorded steps. Elapsed time: 0.4 s.
Two reasons the histogram is not a perfect bell
For coin and uniform steps, a finite number of steps leaves a shape gap, even with infinitely many walkers. Gaussian steps are the exception: their sums are Gaussian already. A finite number of walkers adds sampling variation. Neither is hidden by renormalizing the histogram.
| Sample-to-Gaussian gap | 0.192 |
|---|---|
| Finite-step shape gap | 0.1875 |
| Sampling allowance | 0.043592 |
| Shape plus sampling allowance | 0.23109 |
This sample is within the declared shape-plus-sampling allowance. The sampling allowance has 99.9% coverage for one prespecified comparison under the model, not simultaneous coverage over every trial or observation.
Exact coin probabilities after 4 steps
| Displacement (μm) | Exact fraction |
|---|---|
| −2 | 1 / 16 |
| −1 | 4 / 16 |
| 0 | 6 / 16 |
| 1 | 4 / 16 |
| 2 | 1 / 16 |
Read the histogram as counts and probabilities
| Interval (μm) | Count | Finite-step probability | Gaussian probability |
|---|---|---|---|
| −2.5 to −1.5 | 125 | 0.0625 | 0.060598 |
| −1.5 to −0.5 | 491 | 0.25 | 0.24173 |
| −0.5 to 0.5 | 762 | 0.375 | 0.38292 |
| 0.5 to 1.5 | 502 | 0.25 | 0.24173 |
| 1.5 to 2.5 | 120 | 0.0625 | 0.060598 |
What remains different after many steps?
| Steps | Sample gap | Law gap | Sample mean square (μm²) | Model mean square (μm²) |
|---|---|---|---|---|
| 4 | 0.192 | 0.1875 | 0.9865 | 1 |
| 16 | 0.104 | 0.09819 | 3.997 | 4 |
| 64 | 0.051462 | 0.049673 | 16.021 | 16 |
| 400 | 0.038411 | 0.019935 | 97.652 | 100 |
A particle jostled by molecules takes many small, independent steps. Whatever the shape of one step, so long as it is symmetric and very large steps are rare enough, the spread after many steps grows as the square root of the time, and its shape comes to look like a bell curve.
Section 4 of the Brownian paper supposes an interval τ short compared with any time we observe, but long enough that a particle's motions in successive intervals are independent, and a law φ(Δ) for the displacement Δ in one interval that is symmetric, φ(Δ) = φ(−Δ), and nonzero only for small Δ. Expanding the new distribution in powers of Δ, symmetry removes the odd terms and the second-order term leaves the diffusion equation ∂f/∂t = D ∂2f/∂x2, with D = (1/τ)∫(Δ2/2)φ(Δ)dΔ. From a point start its solution is the Gaussian law of errors, with root-mean-square displacement λx = √(2Dt). The instrument makes the argument concrete with walkers that step every τ = 0.1 s: coin steps of ±0.5 μm, or uniform or Gaussian steps with the same root-mean-square size. All three give D = (0.5 μm)2/(2 × 0.1 s) = 1.25 μm2/s and the same mean square after n steps, n × 0.25 μm2. What differs is the shape. After 4 coin steps the exact distribution is 1, 4, 6, 4 and 1 sixteenths, whose cumulative probability differs from the Gaussian's by up to 0.1875, and the difference shrinks as the steps add up.
Follow one walker. Every τ = 0.1 s it takes a step Δ: with the coin, +0.5 μm or −0.5 μm, equally likely. After n steps its position is the sum xn = Δ1 + Δ2 + … + Δn. Each step averages to zero, because +0.5 and −0.5 are equally likely, so the average position stays at the start. Now square the sum. It contains the n squared steps, Δ12 + … + Δn2, and cross terms such as 2Δ1Δ2. Each squared coin step is exactly 0.25 μm2. A cross term averages to zero when the steps are independent, since Δ1Δ2 is +0.25 μm2 and −0.25 μm2 equally often. So the average of xn2 is n × 0.25 μm2. After 4 steps, 0.4 s, that is 1 μm2, a root-mean-square distance of 1 μm; the 2000 simulated walkers give 0.9865 μm2 and 0.993 μm. Since t = nτ, the mean square is (0.25 μm2/0.1 s) × t, which is 2Dt with D = 0.25/(2 × 0.1) = 1.25 μm2/s, Einstein's D = (1/τ)∫(Δ2/2)φ(Δ)dΔ written for a coin. For the shape, count paths. Four coin steps make 24 = 16 equally likely paths. The walker ends at +2 μm only if all four steps go right, 1 path; at +1 μm if three do, 4 paths; at 0 if two do, 6 paths; then 4 and 1 on the left. So the chances are 1/16, 4/16, 6/16, 4/16 and 1/16, that is 0.0625, 0.25, 0.375, 0.25 and 0.0625, and the walkers' histogram gives 0.0625, 0.2455, 0.381, 0.251 and 0.06. The Gaussian with the same mean square puts 0.383 in the middle bin and 0.061 in each outer one. Einstein's route goes through the diffusion equation instead. The number of particles at x after one more interval is a sum over every displacement Δ that could bring them there, f(x, t + τ) = ∫f(x + Δ, t)φ(Δ)dΔ. Expand f(x + Δ, t) = f + Δ ∂f/∂x + (Δ2/2) ∂2f/∂x2 + …. The term in Δ averages to zero by symmetry, the constant term gives f back, and what is left is τ ∂f/∂t = (∂2f/∂x2) ∫(Δ2/2)φ(Δ)dΔ, the diffusion equation. Two assumptions carry the weight. With a biased coin that steps right 0.6 of the time, the mean step is 0.6 × 0.5 − 0.4 × 0.5 = 0.1 μm and the crowd drifts at 1 μm/s, a first-order term the argument drops. With Cauchy-shaped steps the variance is infinite, and no finite D exists.
Modern qualifications
Einstein reaches D through the diffusion equation, not by adding steps: the 1905 paper never writes the mean square of a sum of n steps, and its τ is an interval chosen for the argument, not a tick of the motion. He called the Gaussian result what was to be expected, the law of random errors, and added that the root-mean-square total displacement in three dimensions is λx√3. Smoluchowski reached the square-root law by a kinetic argument in 1906, with a numerical factor differing from Einstein's by 64/27. Pearson named the random walk in a letter to Nature in 1905, and Rayleigh answered from his 1880 work on vibrations of random phase; Bachelier had used the same diffusion equation for prices in 1900. The shape test here, a Kolmogorov distance with a Dvoretzky–Kiefer–Wolfowitz bound on sampling error, is statistics of 1933 and 1956.
Change an assumption, not just a slider
The next three comparisons are analytical. No biased-coin or Cauchy trajectory is drawn by this instrument.
Remove symmetry: biased left/right jumps
With right-step probability 0.6, the mean step is 0.1 μm. Drift speed is 1 μm/s. The centered-variance coefficient is 1.2 μm²/s.
A nonzero mean step produces drift. The pure-diffusion argument omits that first-order term.
Remove finite variance: Cauchy steps
A positive step interval and finite step moments are required; the Cauchy variance is not finite.
That failure belongs to the pure-diffusion argument, not to the existence of a mathematical Cauchy walk. This preview does not simulate that different transport law.
Shrink the interval: what must stay fixed?
Shrinking the interval at fixed step size makes the coefficient grow without bound. A finite diffusion limit instead keeps step variance divided by twice the interval fixed.
| Interval (s) | Keep step fixed: coefficient (μm²/s) | Reduce step RMS to (μm) | Keep ratio fixed: coefficient (μm²/s) |
|---|---|---|---|
| 0.1 | 1.25 | 0.5 | 1.25 |
| 0.01 | 12.5 | 0.15811 | 1.25 |
| 0.001 | 125 | 0.05 | 1.25 |
| 0.0001 | 1250 | 0.015811 | 1.25 |
Model, trial identity, and numerical limits
Independent symmetric steps with finite variance are assumed. The fixed jumps are a mathematical bridge, not a microscopic theory of tracer collisions. Real tracers need a justified coarse-graining time before independence can be assumed. The three step laws are matched by variance, not fourth moment.
Twenty traces and a bounded set of all-walker checkpoints are retained. A cached observation reads its checkpoint; another observation replays identical counter-indexed draws. Neither creates a different realization. This accepted calculation used 800000 random draws, including 0 replayed draws. The full trial identifies 800000 draws and currently retains 144160 bytes.
The work ceiling is five million walker-steps and the private-recording ceiling is eight MiB. The uniform finite-step shape calculation is bounded to 400 observed steps. Its numerical result is not an interval-arithmetic enclosure. Gaussian draws use the host calculation; cross-engine bitwise parity and FrankenSim WASM conformance are not claimed.
These are model calculations, not experimental evidence. Historical constants and the full control-tape format remain in preparation.
Show the code
The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
kernelDiffusivity · src/physics/reference/diffusion/walkLaws.ts · this site’s source, as built · sha256:b2b39a0e609f3ac519ba4b95fd99332d0170518a6bcf48b5e48b444c378eac0b
This is the function that produced the numbers shown now.
In words
A symmetric step with finite variance has diffusivity equal to that variance divided by twice the step interval.
Implementation
export function kernelDiffusivity(
kernel: StepKernel,
tau: number,
symmetryTolerance = 1e-12,
): Readonly<{
diffusion: ScientificResult;
drift: ScientificResult;
centeredDiffusion: ScientificResult;
}> {
const m = kernelMoments(kernel);
const bad = (id: string, unit: string, reason: string) =>
outside(id, unit, "kernelDiffusivity", "symmetric-finite-variance", reason);
if (
!Number.isFinite(tau) ||
tau <= 0 ||
m.mean.status !== "value" ||
m.variance.status !== "value" ||
typeof m.mean.value !== "number" ||
typeof m.variance.value !== "number"
) {
const reason =
"A positive step interval and finite step moments are required; the Cauchy variance is not finite.";
return {
diffusion: bad("diffusionCoefficient", "m2/s", reason),
drift: bad("driftVelocity", "m/s", reason),
centeredDiffusion: bad("centeredDiffusionCoefficient", "m2/s", reason),
};
}
const centered = value(
"centeredDiffusionCoefficient",
"m2/s",
"kernelDiffusivity",
m.variance.value / (2 * tau),
m.variance.value > 0,
);
return {
diffusion:
Math.abs(m.mean.value) <= symmetryTolerance
? value(
"diffusionCoefficient",
"m2/s",
"kernelDiffusivity",
m.variance.value / (2 * tau),
m.variance.value > 0,
)
: bad(
"diffusionCoefficient",
"m2/s",
"A nonzero mean step produces drift. The pure-diffusion argument omits that first-order term.",
),
drift: value("driftVelocity", "m/s", "kernelDiffusivity", m.mean.value / tau),
centeredDiffusion: centered,
};
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
randomWalkMoments · src/physics/reference/diffusion/walkLaws.ts · this site’s source, as built · sha256:6783075a2530f6028f515501e415352b59fe2d77d084d759a97af6995880ecb9
This function computes the listed outputs when it runs.
In words
After n independent steps the mean-square displacement is n times the step variance.
Implementation
export function randomWalkMoments(
stepRms: number,
tau: number,
n: number,
): Computation<{
mean: number;
meanSquare: number;
rms: number;
elapsedTime: number;
diffusion: number;
}> {
if (!isCount(n) || !Number.isFinite(stepRms) || stepRms <= 0 || !Number.isFinite(tau) || tau <= 0)
return invalid("Use positive finite step RMS and interval, and 0–10000 steps.");
const meanSquare = n * stepRms * stepRms,
diffusion = (stepRms * stepRms) / (2 * tau),
elapsedTime = n * tau;
if (
![meanSquare, diffusion, elapsedTime].every(Number.isFinite) ||
diffusion <= 0 ||
(n > 0 && (meanSquare === 0 || elapsedTime === 0))
)
return numerical("The moment calculation exceeded binary64 range.");
return {
kind: "accepted",
data: { mean: 0, meanSquare, rms: Math.sqrt(meanSquare), elapsedTime, diffusion },
};
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
coinWalkDistribution · src/physics/reference/diffusion/walkLaws.ts · this site’s source, as built · sha256:feae1213b1fc80d262edcbab8d8110da13a122b91baa5378607cf805ebc98855
This function computes the listed outputs when it runs.
In words
A fair coin walk has an exact binomial distribution on the reachable lattice points.
Implementation
/** Exact integer coefficients through n=64; positive center-out recurrence otherwise.
* Central normalization avoids cancellation and factorial overflow. Extreme tails
* beyond binary64 at large n round to zero; no such tails occur in the n<=400 fixtures.
*/
export function coinWalkDistribution(n: number, ell: number): Computation<CoinDistribution> {
if (!isCount(n) || !Number.isFinite(ell) || ell <= 0 || !Number.isFinite(n * ell))
return invalid("Use 0–10000 steps and a positive finite step scale.");
const positions = Float64Array.from({ length: n + 1 }, (_, k) => (2 * k - n) * ell),
probabilities = new Float64Array(n + 1);
if (n <= 64) {
const coefficients: string[] = [];
const denominator = 1n << BigInt(n);
let coefficient = 1n;
for (let k = 0; k <= n; k++) {
coefficients.push(coefficient.toString());
probabilities[k] = Number(coefficient) / Number(denominator);
if (k < n) coefficient = (coefficient * BigInt(n - k)) / BigInt(k + 1);
}
return {
kind: "accepted",
data: { positions, probabilities, coefficients, denominator: denominator.toString() },
};
}
const mid = Math.floor(n / 2);
probabilities[mid] = 1;
for (let k = mid; k < n; k++) {
const pk = probabilities[k] ?? 0;
probabilities[k + 1] = (pk * (n - k)) / (k + 1);
}
for (let k = mid; k > 0; k--) {
const pk = probabilities[k] ?? 0;
probabilities[k - 1] = (pk * k) / (n - k + 1);
}
let total = 0,
correction = 0;
for (const p of probabilities) {
const y = p - correction,
t = total + y;
correction = t - total - y;
total = t;
}
for (let k = 0; k <= n; k++) {
const pk = probabilities[k] ?? 0;
probabilities[k] = pk / total;
}
return { kind: "accepted", data: { positions, probabilities } };
}The site’s own reference code for this law, in TypeScript. It computes the numbers above when the page runs it, and it is what the page uses wherever a FrankenSim result is not available.
recordWalks · src/physics/reference/diffusion/walks.ts · this site’s source, as built · sha256:c55b65639c29f9cba89e6713e2322bd3daa465a91b6f30590ee520916ba71abd
This function computes the listed outputs when it runs.
In words
Draw independent walker steps from the chosen kernel and record a bounded set of traces.
Implementation
export async function recordWalks(
input: WalkSetup,
selectedStep: number,
options: WalkExecutionOptions = {},
): Promise<Computation<WalkRecording>> {
const valid = validate(input);
if (valid.kind !== "accepted") return valid;
const p = valid.data;
if (!Number.isInteger(selectedStep) || selectedStep < 0 || selectedStep > p.runSteps)
return invalid("Observe an integer step within the declared recording.");
let config: ReturnType<typeof execution>;
try {
config = execution(options);
} catch {
return invalid("Use a bounded deterministic chunk size.");
}
if (options.cancelled?.()) return cancelled();
const protectedSteps = new Set([
0,
...WALK_MILESTONES.filter((n) => n <= p.runSteps),
p.runSteps,
]);
const checkpoints = new Map(
[...new Set([...protectedSteps, selectedStep])]
.sort((a, b) => a - b)
.map((n) => [n, new Float64Array(p.walkers)]),
);
const traceValues = new Float64Array(Math.min(WALK_TRACE_COUNT, p.walkers) * (p.runSteps + 1));
const source = options.normals ?? HOST_WALK_NORMALS;
let drawOwner: string | null = null;
let normalVersion = HOST_NORMAL_VERSION;
let work = 0;
for (let walker = 0; walker < p.walkers; walker++) {
const drawn = sampler(p, walker, 0, p.runSteps, source);
if (drawn.kind !== "accepted") return drawn;
// One walk, one producer: every walker's draws must name the same owner.
if (drawOwner !== null && drawn.data.ownerId !== drawOwner)
return failed("The walkers' draws name different producers; no partial trial was accepted.");
drawOwner = drawn.data.ownerId;
normalVersion = drawn.data.normalVersion;
const next = drawn.data.next;
let x = 0;
for (let n = 1; n <= p.runSteps; n++) {
if (work % config.chunk === 0) {
if (options.cancelled?.()) return cancelled();
await config.yieldControl();
if (options.cancelled?.()) return cancelled();
}
x += next();
work++;
if (!Number.isFinite(x))
return failed(
"A walk coordinate exceeded the representable range; no partial trial was accepted.",
);
const checkpoint = checkpoints.get(n);
if (checkpoint) checkpoint[walker] = x;
if (walker < WALK_TRACE_COUNT) traceValues[walker * (p.runSteps + 1) + n] = x;
}
}
if (options.cancelled?.()) return cancelled();
return {
kind: "accepted",
data: Object.freeze({
setup: p,
normals: source,
drawOwner: drawOwner ?? HOST_WALK_DRAW_OWNER,
checkpoints,
traceValues,
protectedSteps,
allocationId: BM05_ALLOCATION.allocationId,
normalVersion,
draws: work * WALK_KERNELS[p.kernel].drawsPerStep,
retainedBytes:
traceValues.byteLength +
[...checkpoints.values()].reduce((sum, a) => sum + a.byteLength, 0),
}),
};
}The explanation
Full explanation
Change the shape of each step while keeping its variance, and compare the spread after many steps. For independent steps the mean square displacement grows in proportion to the number of steps, whatever the shape of a single step.
Show every step of the investigation
Begin with the coin walk you can count exactly, then switch to other step shapes with the same variance. Compare the spread and the shape at several step counts, and check which assumptions the result needs.
An explanatory model, not an observation of nature. This embed starts from the laboratory’s worked defaults, not a saved run. Presentation options change the surrounding guide, never the numerical inputs.