Brownian motion · The distribution argument

Different steps.
The same spreading law?

Begin with a coin walk you can count exactly. Change the shape of each step without changing its variance. Then see what adding many independent steps preserves, and which assumptions the argument needs.

Start with the no-algebra encounter →

Read the argument and open its missing steps →

BM-05 · The independent-step argument

From random steps to diffusion

Ideal model, host calculation

CurrentThese numbers match the current settings.

Model note
  • Primary output stepMean: Host calculation (diffusion.kernelMoments). Owner diffusion.kernelMoments.
  • Primary output stepSecondMoment: Host calculation (diffusion.kernelMoments). Owner diffusion.kernelMoments.
  • Primary output stepFourthMoment: Host calculation (diffusion.kernelMoments). Owner diffusion.kernelMoments.
  • Primary output diffusionCoefficient: Host calculation (diffusion.kernelDiffusivity). Owner diffusion.kernelDiffusivity.
  • Primary output stepKurtosis: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output sampleMean: Host calculation (diffusion.ensembleMoments). Owner diffusion.ensembleMoments.
  • Primary output sampleMeanSquare: Host calculation (diffusion.ensembleMoments). Owner diffusion.ensembleMoments.
  • Primary output sampleRms: Host calculation (diffusion.ensembleMoments). Owner diffusion.ensembleMoments.
  • Primary output modelMeanSquare: Host calculation (diffusion.randomWalkMoments). Owner diffusion.randomWalkMoments.
  • Primary output modelRms: Host calculation (diffusion.randomWalkMoments). Owner diffusion.randomWalkMoments.
  • Primary output elapsedTime: Host calculation (diffusion.randomWalkMoments). Owner diffusion.randomWalkMoments.
  • Primary output samplingTerm: Host calculation (diffusion.dkwBound). Owner diffusion.dkwBound.
  • Primary output walkerCount: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output walkPositions: Host calculation (diffusion.recordWalks). Owner diffusion.recordWalks.
  • Primary output sumKurtosis: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output kolmogorovDistance: Host calculation (diffusion.kolmogorovDistanceToGaussian). Owner diffusion.kolmogorovDistanceToGaussian.
  • Primary output shapeTerm: Host calculation (diffusion.kolmogorovShapeTerm). Owner diffusion.kolmogorovShapeTerm.
  • Primary output agreementBound: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output withinBound: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output histogramEdges: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output histogramCounts: Host calculation (diffusion.displacementHistogram). Owner diffusion.displacementHistogram.
  • Primary output histogramFrequencies: Host calculation (diffusion.displacementHistogram). Owner diffusion.displacementHistogram.
  • Primary output histogramGaussian: Host calculation (diffusion.intervalProbability). Owner diffusion.intervalProbability.
  • Primary output histogramExact: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output underflow: Host calculation (diffusion.displacementHistogram). Owner diffusion.displacementHistogram.
  • Primary output overflow: Host calculation (diffusion.displacementHistogram). Owner diffusion.displacementHistogram.
  • Primary output coinPositions: Host calculation (diffusion.coinWalkDistribution). Owner diffusion.coinWalkDistribution.
  • Primary output coinProbabilities: Host calculation (diffusion.coinWalkDistribution). Owner diffusion.coinWalkDistribution.
  • Primary output coinNumerators: Host calculation (diffusion.coinWalkDistribution). Owner diffusion.coinWalkDistribution.
  • Primary output coinDenominator: Host calculation (diffusion.coinWalkDistribution). Owner diffusion.coinWalkDistribution.
  • Primary output traceTimes: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output traceDisplacements: Host calculation (diffusion.recordWalks). Owner diffusion.recordWalks.
  • Primary output comparisonSteps: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output comparisonSampleMsd: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output comparisonModelMsd: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output comparisonDistance: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output comparisonShape: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output biasedDiffusion: Host calculation (diffusion.kernelDiffusivity). Owner diffusion.kernelDiffusivity.
  • Primary output biasedMean: Host calculation (diffusion.kernelMoments). Owner diffusion.kernelMoments.
  • Primary output biasedDrift: Host calculation (diffusion.kernelDiffusivity). Owner diffusion.kernelDiffusivity.
  • Primary output biasedCenteredDiffusion: Host calculation (diffusion.kernelDiffusivity). Owner diffusion.kernelDiffusivity.
  • Primary output cauchyDiffusion: Host calculation (diffusion.kernelDiffusivity). Owner diffusion.kernelDiffusivity.
  • Primary output continuumLimit: Host calculation (diffusion.continuumLimit). Owner diffusion.continuumLimit.
  • Primary output continuumIntervals: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output fixedStepCoefficients: Host calculation (diffusion.continuumLimit). Owner diffusion.continuumLimit.
  • Primary output fixedRatioSteps: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output fixedRatioCoefficients: Host calculation (diffusion.continuumLimit). Owner diffusion.continuumLimit.
  • Primary output recordingDraws: Host calculation (diffusion.recordWalks). Owner diffusion.recordWalks.
  • Primary output requestDraws: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output replayedDraws: Host calculation (diffusion.observeWalks). Owner diffusion.observeWalks.
  • Primary output reusedRecording: Host calculation (bm05.measure). Owner bm05.measure.
  • Primary output retainedBytes: Host calculation (bm05.measure). Owner bm05.measure.
  • Seed 1905.
  • Accepted input revision 1.
  • Snapshot version 1.
  • Not modeled: A continuous Langevin path; only independent steps of a chosen law.
  • Show the code

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.

Choose a step law and observe

All three sampled laws have the stated step RMS. The bias example below is analytical only and does not change the recorded walk. The uniform finite-step comparison admits at most 400 observed steps.

Observation buttons use the accepted setup, not unsubmitted draft edits. They return to the same trial, not a fresh sample.

Make a prediction

First inspect four steps. Then keep the step RMS and interval unchanged while comparing the laws at 400 steps. Use both the mean square and the shape gap below; a similar-looking histogram alone does not decide the question.

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.

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.

Fraction in each bin0.38292-2.5 μm2.5 μm
Solid bars: all 2000 synthetic endpoints. Short solid marks: the finite-step law. Dashed: Gaussian probabilities over exactly the same bins, not a density curve. Outside the bins: 0 left, 0 right; these walkers remain in every statistic.
Step law and whole-ensemble spread
QuantityAccepted 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

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.

Largest cumulative-probability gap, not a visual fit score
Sample-to-Gaussian gap0.192
Finite-step shape gap0.1875
Sampling allowance0.043592
Shape plus sampling allowance0.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
Binomial counts out of 16 equally likely paths
Displacement (μm)Exact fraction
-21 / 16
-14 / 16
06 / 16
14 / 16
21 / 16
Read the histogram as counts and probabilities
Every bin has the same boundaries for all three columns; the last right endpoint is included
Interval (μm)CountFinite-step probabilityGaussian probability
-2.5 to -1.51250.06250.060598
-1.5 to -0.54910.250.24173
-0.5 to 0.57620.3750.38292
0.5 to 1.55020.250.24173
1.5 to 2.51200.06250.060598
Signed displacement (μm)200 s0.4 s
The first 20 paths, sampled at at most 101 times for drawing. Joining recorded points does not model motion between jumps. These are mathematical walks, not observed molecular collisions.

What remains different after many steps?

Cumulative-probability gap0.1921 step400 steps
Solid: this sample’s largest cumulative-probability gap from the Gaussian. Dashed: the finite-step law’s gap. The step axis is logarithmic. Lines only join the evaluated step counts; fluctuations in a finite sample need not decrease at every observation.
Same recorded trial: shape and spread at each comparison
StepsSample gapLaw gapSample mean square (μm²)Model mean square (μm²)
40.1920.18750.98651
160.1040.098193.9974
640.0514620.04967316.02116
4000.0384110.01993597.652100

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.

Two limiting procedures, calculated from the accepted step scale
Interval (s)Keep step fixed: coefficient (μm²/s)Reduce step RMS to (μm)Keep ratio fixed: coefficient (μm²/s)
0.11.250.51.25
0.0112.50.158111.25
0.0011250.051.25
0.000112500.0158111.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. The source-aligned critical edition, reviewed historical constants, and full control-tape format remain in preparation.

Show the code

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

kernelDiffusivity · src/physics/reference/diffusion/walkLaws.ts · revision workspace · sha256:b2b39a0e609f3ac519ba4b95fd99332d0170518a6bcf48b5e48b444c378eac0b

This is the function that produced the current snapshot.

In words

A symmetric step with finite variance has diffusivity equal to that variance divided by twice the step interval.

Mathematics

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,
  };
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

randomWalkMoments · src/physics/reference/diffusion/walkLaws.ts · revision workspace · 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.

Mathematics

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 },
  };
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

coinWalkDistribution · src/physics/reference/diffusion/walkLaws.ts · revision workspace · 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.

Mathematics

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 } };
}

Audited TypeScript reference evaluator: the owner on this device, or the host fallback for a FrankenSim capability.

recordWalks · src/physics/reference/diffusion/walks.ts · revision workspace · sha256:d8d45c494c5a564337a3ad369543562ad3d53b207e4cb39113cf70f28a54f64c

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.

Mathematics

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));
  let work = 0;
  for (let walker = 0; walker < p.walkers; walker++) {
    const next = sampler(p, walker);
    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,
      checkpoints,
      traceValues,
      protectedSteps,
      allocationId: BM05_ALLOCATION.allocationId,
      normalVersion: HOST_NORMAL_VERSION,
      draws: work * WALK_KERNELS[p.kernel].drawsPerStep,
      retainedBytes:
        traceValues.byteLength +
        [...checkpoints.values()].reduce((sum, a) => sum + a.byteLength, 0),
    }),
  };
}

Open the argument

Why the second moment survives

Write a walker’s position after n steps as the sum of its displacements. A symmetric step has zero mean. Independence makes the cross terms in the square average to zero; the n individual squared steps remain.

xn=j=1nΔj,Δ=0,xn2=nΔ2x_n=\sum_{j=1}^{n}\Delta_j,\qquad \langle\Delta\rangle=0,\qquad \langle x_n^2\rangle=n\langle\Delta^2\rangle

With one step every τ seconds, elapsed time is nτ. The coefficient connecting mean square with time is therefore fixed by the variance of one step divided by twice its interval.

D=Δ22τ,x2=2Dt,x2tD=\frac{\langle\Delta^2\rangle}{2\tau},\qquad \langle x^2\rangle=2Dt,\qquad \sqrt{\langle x^2\rangle}\propto\sqrt{t}

From a finite jump to a continuous density

The next position distribution is the old one shifted by every allowed step, weighted by the probability of that step. Expanding the shifted density explains the role of symmetry: the first-order spatial term vanishes, and the second-order term contains the same coefficient.

p(x,t+τ)=p(xΔ,t)φ(Δ)dΔp(x,t+\tau)=\int p(x-\Delta,t)\varphi(\Delta)\,d\Delta
pt=D2px2\frac{\partial p}{\partial t}=D\frac{\partial^2p}{\partial x^2}

This continuous equation is a limiting description, not an assertion that four discrete jumps already have a continuous Gaussian distribution. The shape gap in the laboratory makes that distinction visible. A biased mean leaves a drift term; an infinite variance does not supply the finite second-order coefficient used here.

A calculation is not an observation

Agreement between the synthetic walks and their limiting law tests the numerical implementation of the assumptions. It does not establish that a real suspension satisfies them. This is a modern explanation of the argument; the reviewed German and aligned English critical edition is still in preparation.