codex/entropy-rate-binary-source-and-innovations.py

entropy-rate-binary-source-and-innovations.py
"""Illustrate an original binary Markov-source model; write the PNG to cwd."""
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def main():
    rng = np.random.default_rng(7391)
    n, q = 80, 1 / 8
    flips = rng.random(n - 1) < q
    source = np.empty(n, dtype=int)
    source[0] = rng.integers(0, 2)
    for i in range(1, n):
        source[i] = source[i - 1] ^ int(flips[i - 1])
    independent = rng.integers(0, 2, size=n)
    assert np.array_equal(source[1:] ^ source[:-1], flips.astype(int))
    plt.rcParams.update({"font.size": 12, "axes.titlesize": 14})
    fig, axes = plt.subplots(3, 1, figsize=(12, 7.2), dpi=100, sharex=True)
    fig.patch.set_facecolor("white")
    t = np.arange(1, n + 1)
    axes[0].step(t, source, where="post", color="#287557", linewidth=2)
    axes[0].scatter(t, source, color="#287557", s=10)
    axes[0].set_title("Persistent source: each marginal bit is fair, but transitions usually repeat")
    axes[0].set_ylabel(r"$X_n$")
    axes[1].vlines(t[1:][flips], 0, 1, color="#a44a27", linewidth=2)
    axes[1].scatter(t[1:], flips.astype(int), color="#a44a27", s=15)
    axes[1].set_title(r"Flip decisions: $Z_n=X_n\oplus X_{n-1}$, independent with probability $q=1/8$")
    axes[1].set_ylabel(r"$Z_n$")
    axes[1].text(1, 0.6, "Initial bit\nis sent separately", fontsize=10,
                 bbox={"facecolor": "white", "edgecolor": "#dddddd", "pad": 4})
    axes[2].step(t, independent, where="post", color="#476c9b", linewidth=1.6)
    axes[2].scatter(t, independent, color="#476c9b", s=9)
    axes[2].set_title("Comparison: independent fair bits, with one new bit of uncertainty per symbol")
    axes[2].set_ylabel("IID bit")
    for ax in axes:
        ax.set_ylim(-0.18, 1.22)
        ax.set_yticks([0, 1])
        ax.grid(axis="x", alpha=0.16)
    axes[2].set(xlim=(0.5, n + 0.5), xlabel="Symbol index n")
    fig.suptitle("A fair marginal distribution does not imply independent symbols", fontsize=18)
    fig.text(0.5, 0.018, "Original simulated paths, seed 7391; finite counts do not prove the theoretical entropy rate",
             ha="center", fontsize=11)
    fig.subplots_adjust(left=0.07, right=0.98, top=0.865, bottom=0.10, hspace=0.67)
    fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"), facecolor="white", transparent=False)
    plt.close(fig)


if __name__ == "__main__":
    main()