import sys
import matplotlib.pyplot as plt
import numpy as np
from io import StringIO

plt.rcParams.update({'text.color': '#808080', 'axes.labelcolor': '#808080', 'axes.edgecolor': '#999999',
                     'xtick.color': '#808080', 'ytick.color': '#808080'})

# The lesson's noisy XOR (same seed) and its hand-built 2-2-1 network, sigmoid version (weights × 10)
rng = np.random.default_rng(0)
corners = rng.integers(0, 2, size=(400, 2))
X = corners + rng.normal(0, 0.2, size=(400, 2))
y = corners[:, 0] ^ corners[:, 1]

sigmoid = lambda z: 1 / (1 + np.exp(-z))
W1, b1 = np.array([[1, 1], [1, 1]]), np.array([-0.5, -1.5])
w2, b2 = np.array([1, -1]), -0.5
H = sigmoid(10 * (X @ W1.T + b1))
pred = (H @ w2 + b2 > 0).astype(int)
acc = (pred == y).mean()
print(f"hand-built network on the 400 noisy points: accuracy {acc:.3f}", file=sys.stderr)

fig, (a1, a2) = plt.subplots(1, 2, figsize=(9.5, 4.6))
lo, hi = -0.8, 1.8
t = np.linspace(lo, hi, 2)
a1.fill_between(t, 0.5 - t, 1.5 - t, color='#58a6ff', alpha=0.10, lw=0)
a1.plot(t, 0.5 - t, color='#3fb950', lw=1.6, label='h₁ (OR) line: x₁ + x₂ = 0.5')
a1.plot(t, 1.5 - t, color='#ff7b72', lw=1.6, label='h₂ (AND) line: x₁ + x₂ = 1.5')
for c, col, lab in [(0, '#f0883e', 'class 0: near (0,0) and (1,1)'), (1, '#58a6ff', 'class 1: near (0,1) and (1,0)')]:
    a1.scatter(X[y == c, 0], X[y == c, 1], s=9, color=col, label=lab)
a1.set_xlim(lo, hi); a1.set_ylim(lo, hi); a1.set_aspect('equal')
a1.set_xlabel('x₁', fontsize=9); a1.set_ylabel('x₂', fontsize=9)
a1.set_title('input space: no single line separates the classes', fontsize=9)
a1.legend(fontsize=7.5, loc='upper center', bbox_to_anchor=(0.5, -0.13), ncol=2, framealpha=0)

jit = rng.normal(0, 0.015, size=H.shape)             # a hair of jitter so stacked points stay visible
for c, col in [(0, '#f0883e'), (1, '#58a6ff')]:
    a2.scatter(H[y == c, 0] + jit[y == c, 0], H[y == c, 1] + jit[y == c, 1], s=9, color=col, alpha=0.6)
t2 = np.linspace(-0.2, 1.45, 2)
a2.plot(t2, t2 - 0.5, color='gray', lw=1.6)
a2.text(0.55, -0.15, 'output line: h₁ − h₂ = 0.5', color='gray', fontsize=8.5)
for (hx, hy), lab, ha in [((0, 0.09), '(0,0)', 'center'), ((1.05, 0.93), '(1,1)', 'left'),
                          ((1.05, 0.07), '(0,1) and\n(1,0)', 'left')]:
    a2.text(hx, hy, lab, ha=ha, fontsize=8)
a2.set_xlim(-0.2, 1.45); a2.set_ylim(-0.2, 1.2); a2.set_aspect('equal')
a2.set_xlabel('h₁ = σ(10(x₁ + x₂ − 0.5))', fontsize=9); a2.set_ylabel('h₂ = σ(10(x₁ + x₂ − 1.5))', fontsize=9)
a2.set_title(f'hidden space: one line separates them (accuracy {acc:.3f})', fontsize=9)
for ax in (a1, a2):
    ax.tick_params(labelsize=7.5)
plt.tight_layout()

buffer = StringIO()
plt.savefig(buffer, format="svg", transparent=True)
print(buffer.getvalue())

plt.close()
