codex/anderson-participation-disorder.py

anderson-participation-disorder.py
"""Participation in finite open Anderson chains; no inferred critical disorder.

Python 3.14 / NumPy 2.3.5 / Matplotlib 3.10.7. Run from _media.
Each sample uses the four eigenstates nearest E=0; plotted samples are their
mean participation ratios, not pooled eigenstates. The same underlying
random potential is scaled across W within each realization and size.
"""
import argparse
import json
from pathlib import Path

import matplotlib.pyplot as plt
import numpy as np


def sample_participation(unit_potential, width):
    n = len(unit_potential)
    h = np.diag(width * unit_potential) - np.eye(n, k=1) - np.eye(n, k=-1)
    energy, vectors = np.linalg.eigh(h)
    np.testing.assert_allclose(np.sum(abs(vectors) ** 2, axis=0), 1, atol=2e-14, rtol=0)
    np.testing.assert_allclose(vectors.T @ vectors, np.eye(n), atol=2e-14, rtol=0)
    np.testing.assert_allclose(h @ vectors, vectors * energy, atol=2e-14, rtol=0)
    p = 1 / np.sum(abs(vectors) ** 4, axis=0)
    assert np.all(p >= 1 - 1e-12) and np.all(p <= n + 1e-12)
    return float(np.mean(p[np.argsort(abs(energy), kind='stable')[:4]]))


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--sizes', type=int, nargs='+', default=[40, 80])
    parser.add_argument('--realizations', type=int, default=24)
    parser.add_argument('--seed', type=int, default=20261016)
    args = parser.parse_args()
    if any(not 40 <= n <= 100 or n % 2 for n in args.sizes) or not 4 <= args.realizations <= 64:
        parser.error('sizes must be even in 40..100; realizations must be 4..64')
    widths = np.array([0, 0.5, 1, 2, 3, 4, 6, 8.0])
    plt.rcParams.update({'font.size': 11, 'figure.facecolor': 'white', 'axes.facecolor': 'white'})
    fig, axes = plt.subplots(1, 2, figsize=(10, 4.8))
    fig.suptitle('Disorder reduces participation; finite samples vary', fontsize=14)
    summaries = []
    for i, n in enumerate(args.sizes):
        rng = np.random.default_rng(np.random.SeedSequence([args.seed, n]))
        potentials = rng.uniform(-0.5, 0.5, (args.realizations, n))
        values = np.array([[sample_participation(v, w) for w in widths] for v in potentials])
        np.testing.assert_allclose(values[:, 0], 2 * (n + 1) / 3, atol=2e-12, rtol=0)
        low, mid, high = np.quantile(values, [0.1, 0.5, 0.9], axis=0)
        color = ['#235f93', '#b56c24', '#487542'][i % 3]
        for ax, scale in zip(axes, [1, n]):
            for row in values:
                ax.plot(widths, row / scale, color=color, alpha=0.12, lw=0.65)
            ax.fill_between(widths, low / scale, high / scale, color=color, alpha=0.12)
            ax.plot(widths, mid / scale, 'o-', color=color, label=f'N = {n}: median, 10–90% band', ms=4)
        summaries.append({'N': n, 'median_P': mid.tolist(), 'q10_P': low.tolist(), 'q90_P': high.tolist()})
    axes[0].set_ylabel('Mean P of four states nearest E = 0')
    axes[1].set_ylabel('Mean P / N of the same four states')
    axes[0].set_ylim(bottom=0)
    axes[1].set_ylim(0, 0.8)
    for ax in axes:
        ax.set_xlabel('Disorder W/t (full uniform box width)')
        ax.grid(alpha=0.2)
        ax.legend(fontsize=9, loc='upper right')
        ax.set_xlim(0, 8)
    fig.subplots_adjust(left=0.075, right=0.985, top=0.87, bottom=0.20, wspace=0.25)
    fig.text(0.5, 0.018, f'{args.realizations} realizations per size, seed {args.seed}; faint lines are samples. No universal threshold is inferred.', ha='center', fontsize=10)
    fig.savefig(Path(__file__).stem + '.png', dpi=120, facecolor='white', transparent=False)
    print(json.dumps({'widths': widths.tolist(), 'realizations': args.realizations, 'seed': args.seed,
                      'state_selection': 'four eigenstates closest to E=0, sample mean P',
                      'summaries': summaries, 'checks': ['all eigenvector normalizations', 'orthogonality',
                      'eigenvalue residuals', 'all P bounds', 'analytic clean P for every realization']}))


if __name__ == '__main__':
    main()