"""Analytical illustrations; no hardware measurements. Run with Python + NumPy + Matplotlib."""
from pathlib import Path
import csv
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
out=Path(__file__).resolve().parent
plt.rcParams.update({'font.family':'DejaVu Sans','font.size':10,'axes.spines.top':False,'axes.spines.right':False,'axes.titleweight':'bold','svg.fonttype':'none','figure.facecolor':'#faf9f4','axes.facecolor':'#faf9f4','text.color':'#183544','axes.labelcolor':'#183544'})
s=np.array([8000,16000,32000,64000,128000,256000,270000,384000,512000,768000,1024000],dtype=np.float64)
b=1;L=32;hq=32;hkv=8;d=128;p=2
scores=b*hq*s*s*p/2**30
kv=2*b*L*s*hkv*d*p/2**30
state=32/1024 # 32 MiB assumed recurrent allocation, in GiB
hybrid=kv*3/32+state
with (out/'analytical-data.csv').open('w',newline='') as f:
 w=csv.writer(f);w.writerow(['tokens','relative_quadratic_work','relative_linear_work','naive_score_one_layer_GiB','KV_32_layers_GiB','hybrid_3_attention_layers_plus_assumed_32MiB_GiB','assumed_recurrent_state_GiB'])
 for i,n in enumerate(s):w.writerow([int(n),(n/8000)**2,n/8000,scores[i],kv[i],hybrid[i],state])
def save(fig,name):
 fig.tight_layout(pad=1.8);fig.savefig(out/(name+'.svg'),bbox_inches='tight');fig.savefig(out/(name+'.png'),dpi=170,bbox_inches='tight');plt.close(fig)
fig,ax=plt.subplots(figsize=(8.4,4.4));ax.plot(s/1000,(s/8000)**2,'o-',color='#b55c32',label='Dense attention pairwise work: relative S²');ax.plot(s/1000,s/8000,'s-',color='#227b7b',label='Linear sequence term: relative S');ax.plot(s/1000,np.ones(len(s)),'--',color='#73629b',label='Fixed-size state storage: constant');ax.set(yscale='log',xlabel='Sequence length (thousand tokens)',ylabel='Relative units (each curve = 1 at 8k)',title='Different scaling laws — not measured latency');ax.grid(axis='y',alpha=.2);ax.legend(fontsize=8,loc='upper left');save(fig,'scaling-laws')
fig,ax=plt.subplots(figsize=(8.4,4.4));ax.plot(s/1000,scores,'o-',color='#b55c32',label='Naive score matrix, one layer / 32 query heads');ax.plot(s/1000,kv,'s-',color='#227b7b',label='KV-cache, 32 layers / 8 KV heads');ax.axvline(270,color='#807e76',ls=':',lw=1);ax.annotate('270k is an example, not a threshold',(270,30),xytext=(365,7),fontsize=8,arrowprops={'arrowstyle':'-','color':'#807e76'});ax.set(yscale='log',xlabel='Sequence length (thousand tokens)',ylabel='Memory (GiB, logarithmic scale)',title='Two different allocations: S² scores versus S cache');ax.grid(axis='y',alpha=.2);ax.legend(fontsize=8);save(fig,'score-vs-cache')
fig,ax=plt.subplots(figsize=(8.4,4.4));ax.plot(s/1000,kv,'s-',color='#227b7b',label='Illustrative dense model: 32 attention layers');ax.plot(s/1000,hybrid,'o-',color='#b55c32',label='Illustrative hybrid: 3 attention layers + 32 MiB state');ax.plot(s/1000,np.full(len(s),state),'--',color='#73629b',label='Pure recurrent cache: assumed 32 MiB state');ax.set(yscale='log',xlabel='Sequence length (thousand tokens)',ylabel='Persistent sequence memory (GiB, log scale)',title='Hybrid attention keeps a context-dependent cache');ax.grid(axis='y',alpha=.2);ax.legend(fontsize=8);save(fig,'hybrid-cache')
print(f'270k: naive scores {scores[6]:.2f} GiB, KV {kv[6]:.2f} GiB, illustrative hybrid {hybrid[6]:.2f} GiB')
