codexbinary-channel-information.py
binary-channel-information.py
"""Plot binary-channel information and joint probabilities; save to cwd."""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def binary_entropy(q):
q = np.asarray(q, dtype=float)
out = np.zeros_like(q)
interior = (q > 0) & (q < 1)
p = q[interior]
out[interior] = -p * np.log2(p) - (1 - p) * np.log2(1 - p)
return out
def main():
q = np.linspace(0, 1, 801)
h = binary_entropy(q)
assert np.allclose(binary_entropy([0, .5, 1]), [0, 1, 0])
plt.rcParams.update({'font.size': 12})
fig = plt.figure(figsize=(11, 7.2), layout='constrained', facecolor='white')
grid = fig.add_gridspec(2, 3, height_ratios=[1.7, 1])
ax = fig.add_subplot(grid[0, :])
ax.plot(q, h, color='#d87921', linewidth=2.5, label='Error uncertainty: H(Y|X) = h2(q)')
ax.plot(q, 1-h, color='#2563a6', linewidth=2.5, label='Retained information: I(X;Y) = 1 - h2(q)')
chosen_q = .1
chosen_i = float(1 - binary_entropy([chosen_q])[0])
ax.scatter([chosen_q], [chosen_i], color='#2563a6', zorder=3)
ax.annotate('q = 0.1: %.3f bits retained' % chosen_i, (chosen_q, chosen_i),
xytext=(.18, .68), arrowprops={'arrowstyle': '->'}, fontsize=10)
ax.set(xlabel='Bit-flip probability q', ylabel='Bits per channel use',
xlim=(0, 1), ylim=(-.03, 1.16), title='A fair input bit: random errors lose information, certain flips do not')
ax.grid(alpha=.2)
ax.legend(loc='upper center', fontsize=10)
for i, noise in enumerate([0, .5, 1]):
a = fig.add_subplot(grid[1, i])
joint = .5 * np.array([[1-noise, noise], [noise, 1-noise]])
a.imshow(joint, vmin=0, vmax=.5, cmap='Blues')
for x in range(2):
for y in range(2):
a.text(y, x, '%.2f' % joint[x, y], ha='center', va='center',
color='white' if joint[x, y] > .3 else '#142738', fontsize=15)
a.set(xticks=[0, 1], yticks=[0, 1], xlabel='Output Y', ylabel='Input X',
title=['q = 0: unchanged', 'q = 0.5: independent', 'q = 1: inverted'][i])
fig.suptitle('Joint probabilities P(X,Y) below; both marginals remain fair', fontsize=14)
fig.savefig(Path.cwd() / 'binary-channel-information.png', dpi=120, facecolor='white')
plt.close(fig)
if __name__ == '__main__':
main()