codexsherman-morrison-near-singularity.py
sherman-morrison-near-singularity.py
"""Inverse amplification near a singular rank-one update; PNG to CWD."""
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
def amplification(delta):
"""Use positive delta = 1 + t explicitly to avoid subtractive cancellation."""
u = np.array([1., 2.])
v = np.array([3., -1.])
correction = np.outer(u, v)
t = delta - 1
matrix = np.eye(2) + t * correction
inverse = np.eye(2) - (t / delta) * correction
norm = np.linalg.norm(inverse, 2)
condition = np.linalg.norm(matrix, 2) * norm
return norm, condition
def main():
plt.rcParams.update({"font.size": 12, "figure.facecolor": "white"})
delta = np.logspace(-4, 0, 501)
data = np.array([amplification(value) for value in delta])
fig, (left, right) = plt.subplots(1, 2, figsize=(12, 5.3), dpi=100)
left.loglog(delta, data[:, 0], color="#246bce", linewidth=2.5,
label=r"$\|B^{-1}\|_2$")
left.loglog(delta, 1 / delta, color="#69747d", linestyle="--", linewidth=1.8,
label=r"Direction $u$ gives lower bound $1/\delta$")
right.loglog(delta, data[:, 1], color="#bf5520", linewidth=2.5,
label=r"$\kappa_2(B)=\|B\|_2\|B^{-1}\|_2$")
marked_norm, marked_condition = amplification(0.01)
for ax, value, text, color in [
(left, marked_norm, "δ = 0.01, t = −0.99\nInverse norm ≈ 700.179", "#246bce"),
(right, marked_condition, "δ = 0.01, t = −0.99\nCondition number ≈ 4902.500", "#bf5520"),
]:
ax.scatter([0.01], [value], color=color, zorder=5)
ax.annotate(text, (0.01, value), xytext=(0.025, value * 6),
textcoords="data", fontsize=10,
arrowprops={"arrowstyle": "-", "color": color},
bbox={"facecolor": "white", "edgecolor": "none", "pad": 2})
ax.set(xlabel=r"Nonzero denominator $\delta=1+t$", xlim=(1e-4, 1))
ax.grid(which="both", alpha=0.16)
ax.legend(loc="lower left", frameon=False, fontsize=10)
left.set_ylabel("Maximum inverse amplification")
right.set_ylabel("Spectral condition number")
left.set_title("The inverse amplifies inputs", weight="bold", fontsize=13)
right.set_title("The updated system becomes sensitive", weight="bold", fontsize=13)
fig.suptitle("Approaching δ = 0 makes the rank-one update singular",
fontsize=16, weight="bold", y=0.975)
fig.subplots_adjust(left=0.08, right=0.97, bottom=0.15, top=0.80, wspace=0.28)
fig.savefig(Path.cwd() / Path(__file__).with_suffix(".png").name,
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()