File size: 14,148 Bytes
43b947d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229


<header>
 <div class="kicker">Live proof &middot; real weights &middot; nothing canned</div>
 <h1 class="serif">&mu;Lattice: the growing memory, running</h1>
 <p class="dek serif">A one-million-parameter lattice mixer that stores associations while it
 reads, overwrites them on sight, and answers from memory &mdash; at constant cost per token.
 This page drives the actual trained checkpoint on the GPU.</p>
 <div class="meta" id="meta">model: capacity8k.pt &middot; loading&hellip;</div>
</header>
<main>

<section>
 <div class="sn"><span class="n">01</span><h2 class="serif">Stream your own document</h2></div>
 <p class="lead">Paste any text. Define your own facts as <em>name &rarr; value</em> pairs. Mark any
 of them to be <strong>overwritten mid-stream</strong> with a new value. Then ask. The model reads
 your words as the stream, stores your pairs as it passes them, and must return the
 <em>latest</em> value &mdash; last write wins.</p>
 <div class="fig">
  <div class="grid2">
   <div>
    <label for="doc">Your text (becomes the stream)</label>
    <textarea id="doc">The harbour was quiet that morning. Gulls circled the masts while the tide went out. A clerk stamped papers without looking up. Somewhere a bell rang twice, then stopped. The road east had been washed out again. Dust settled over the market stalls. Two children argued about a kite. Rain threatened but never came.</textarea>
   </div>
   <div>
    <label>Your facts <span class="note">(name &rarr; value; fill &ldquo;new value&rdquo; to overwrite mid-stream)</span></label>
    <div class="pairs" id="pairs"></div>
    <button class="sec" id="addp" style="margin-top:8px;padding:6px 16px;font-size:13px">+ add fact</button>
   </div>
  </div>
  <button id="runc">Read, store, overwrite &mdash; and answer</button>
  <div class="stats" id="stc" style="display:none"></div>
  <div id="cres" style="display:none">
   <table id="qrt"></table>
   <div class="figcap" id="ccap"></div>
  </div>
 </div>
</section>

<section>
 <div class="sn"><span class="n">02</span><h2 class="serif">The store at scale</h2></div>
 <p class="lead">The same mechanism under load: up to 8,192 pairs in one 133,120-token stream,
 half of them overwritten, answered after a single causal pass. The map shows the model&rsquo;s
 own learned addresses &mdash; distinct keys spread, exactly as the design intends.</p>
 <div class="fig">
  <div class="row">
   <div class="rangewrap"><label style="margin:0">pairs</label>
    <input id="np" type="range" min="64" max="8192" step="64" value="2048"><span class="rv" id="npv">2048</span></div>
   <div class="rangewrap"><label style="margin:0">filler/pair</label>
    <input id="fl" type="range" min="0" max="14" value="14"><span class="rv" id="flv">14</span></div>
   <div class="rangewrap"><label style="margin:0">overwritten</label>
    <input id="ow" type="range" min="0" max="50" value="50"><span class="rv" id="owv">50%</span></div>
   <button class="sec" id="run" style="margin-top:0">stream &amp; query</button>
  </div>
  <div class="stats" id="st" style="display:none"></div>
  <div class="row" style="align-items:stretch" id="bigres" >
   <canvas id="latt" height="280" style="flex:1.2;min-width:300px"></canvas>
   <div style="flex:1;min-width:280px;max-height:300px;overflow:auto">
    <table id="qr"></table></div>
  </div>
  <div class="figcap">Left: learned addresses of 400 stored keys from this run (grid scale shown).
   Right: 64 sampled queries; gold rows marked <span class="pill">overwritten</span> were
   re-written later in the stream &mdash; the store must answer with the new value.</div>
 </div>
</section>

<section>
 <div class="sn"><span class="n">03</span><h2 class="serif">Constant cost while memory grows</h2></div>
 <p class="lead">Each token touches exactly nine memory cells, so per-token work cannot grow with
 context. Measure it: the curve below runs the model at increasing stream lengths, live.</p>
 <div class="fig">
  <button class="sec" id="cost" style="margin-top:0">measure the cost curve</button>
  <canvas id="cc" height="300" style="margin-top:14px"></canvas>
  <div class="figcap">Blue: measured &mu;s per token &mdash; flat is the guarantee. Green: lattice
   cells, growing with stored content. Dashed red: attention&rsquo;s O(T&sup2;) work, analytic reference.</div>
 </div>
</section>

<section>
 <div class="sn"><span class="n">04</span><h2 class="serif">Inside one cell</h2></div>
 <p class="lead">Where does a value physically live, and where does the <em>new</em> value go on
 overwrite? Pick one fact from section 01 (or any name/value). The model&rsquo;s learned address
 for that key, the 3&times;3 cells it touches, and the before/after answers &mdash; same cells,
 value replaced in place by the delta rule.</p>
 <div class="fig">
  <div class="grid2">
   <div>
    <label>fact to inspect</label>
    <div class="prow" style="grid-template-columns:1fr 1fr 1fr">
     <input id="cvn" placeholder="name" value="the vault password">
     <input id="cvv" placeholder="value" value="swordfish">
     <input id="cvnv" placeholder="new value" value="bluedragon"></div>
    <button class="sec" id="cv">inspect the cell</button>
    <div id="cvs" style="display:none;margin-top:14px"></div>
   </div>
   <div><canvas id="cellcv" height="300"></canvas>
    <div class="figcap" id="cvcap"></div></div>
  </div>
 </div>
</section>

</main>
<footer>Every number on this page is produced by a live forward pass of
<code>capacity8k.pt</code> on request &mdash; timestamped per run. Filler for section 01 is your own
text, hashed deterministically into the model&rsquo;s token space; facts occupy key&ndash;value
structural positions, exactly the regime the mixer was trained on.</footer>
<script>
const $=id=>document.getElementById(id);
const esc=s=>String(s).replace(/[&<>"]/g,c=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c]));
async function api(p,body){const r=await fetch(p,{method:"POST",
 headers:{"Content-Type":"application/json"},body:JSON.stringify(body)});return r.json()}
function stats(el,d){el.style.display="grid";
 const s=[["stream tokens",d.T.toLocaleString()],["time",d.wall_s+" s"],
  ["&mu;s/token",d.us_per_token],["cells",d.cells.toLocaleString()],["recall",d.acc]];
 el.innerHTML=s.map(x=>`<div class="stat"><b>${x[1]}</b><span>${x[0]}</span></div>`).join("")}
/* section 01 */
const DEF=[["the vault password","swordfish","bluedragon"],
 ["Elbaz's first name","Eric",""],["the car's color","red",""],
 ["the meeting time","3pm","4pm"],["the favorite meal","stew",""]];
function prow(n,v,nv){const d=document.createElement("div");d.className="prow";
 d.innerHTML=`<input placeholder="name" value="${esc(n)}">
  <input placeholder="value" value="${esc(v)}">
  <input placeholder="new value (optional)" value="${esc(nv)}">
  <button class="del" title="remove">&times;</button>`;
 d.querySelector(".del").onclick=()=>d.remove();return d}
DEF.forEach(x=>$("pairs").appendChild(prow(...x)));
$("addp").onclick=()=>$("pairs").appendChild(prow("","",""));
$("runc").onclick=async()=>{$("runc").disabled=true;$("runc").textContent="reading your stream&hellip;";
 try{
  const pairs=[...document.querySelectorAll("#pairs .prow")].map(r=>{
   const i=r.querySelectorAll("input");return{name:i[0].value.trim(),value:i[1].value.trim(),
    new_value:i[2].value.trim()}}).filter(p=>p.name&&p.value);
  const d=await api("/api/custom",{text:$("doc").value,pairs,seed:(Math.random()*1e6)|0});
  if(d.error){alert(d.error);return}
  $("meta").textContent=`capacity8k.pt · scale ${d.scale||96} · ${d.device} · run ${d.ts}`;
  stats($("stc"),d);
  $("qrt").innerHTML=`<tr><th>asked</th><th>the model answered</th><th>latest value</th><th></th></tr>`+
   d.rows.map(r=>`<tr><td><b>${esc(r.name)}</b></td>
    <td class="${r.ok?"y":"n"}">${esc(r.asked)}</td>
    <td class="${r.updated?"updv":""}">${esc(r.truth)}</td>
    <td>${r.updated?`<span class="pill">was ${esc(r.old)}</span>`:""}${r.ok?"":" ✗"}</td></tr>`).join("");
  $("cres").style.display="block";
  $("ccap").innerHTML=`${d.n_pairs} of your facts stored in ${d.T.toLocaleString()} tokens of your text`+
   (d.n_upd?`, ${d.n_upd} overwritten mid-stream`:"")+` · recall <b>${d.acc}</b> · ${d.us_per_token} &mu;s/token`+
   ` · key ids: `+Object.entries(d.keymap).slice(0,4).map(([n,k])=>`${esc(n)}=${k}`).join(", ")+`&hellip;`;
 }catch(e){alert(e)}$("runc").disabled=false;$("runc").textContent="Read, store, overwrite — and answer"};
/* section 02 */
$("np").oninput=e=>$("npv").textContent=e.target.value;
$("fl").oninput=e=>$("flv").textContent=e.target.value;
$("ow").oninput=e=>$("owv").textContent=e.target.value+"%";
function drawLatt(pts,sc){const c=$("latt"),x=c.getContext("2d");
 c.width=c.clientWidth*2;c.height=560;x.scale(2,2);const W=c.width/2,H=280;
 x.fillStyle="#fff";x.fillRect(0,0,W,H);
 x.strokeStyle="#eceef2";for(let i=0;i<=8;i++){const p=i/8;
  x.beginPath();x.moveTo(p*W,0);x.lineTo(p*W,H);x.stroke();
  x.beginPath();x.moveTo(0,p*H);x.lineTo(W,p*H);x.stroke()}
 x.fillStyle="#2547d0";for(const p of pts){const u=(p[0]/sc+1)/2,v=(p[1]/sc+1)/2;
  x.beginPath();x.arc(u*W,v*H,1.7,0,7);x.fill()}}
$("run").onclick=async()=>{$("run").disabled=true;$("run").textContent="streaming&hellip;";
 try{const d=await api("/api/store",{n_pairs:+$("np").value,filler:+$("fl").value,
  overwrite_frac:+$("ow").value/100,seed:(Math.random()*1e6)|0});
  $("meta").textContent=`capacity8k.pt · scale ${d.scale} · ${d.params.toLocaleString()} params · ${d.device} · run ${d.ts}`;
  stats($("st"),d);drawLatt(d.addr_points,d.scale);
  $("qr").innerHTML=`<tr><th>query key</th><th>answered</th><th>true</th><th></th></tr>`+
   d.rows.map(r=>`<tr><td>${r.key}</td><td class="${r.ok?"y":"n"}">${r.pred}</td>`+
   `<td class="${r.updated?"updv":""}">${r.gold}</td>`+
   `<td>${r.updated?'<span class="pill">overwritten</span>':""}${r.ok?"":" ✗"}</td></tr>`).join("");
 }catch(e){alert(e)}$("run").disabled=false;$("run").textContent="stream & query"};
/* section 03 */
function drawCC(data){const c=$("cc"),x=c.getContext("2d");c.width=c.clientWidth*2;c.height=600;
 x.scale(2,2);const W=c.width/2,H=300,P=48;
 const maxT=Math.max(...data.map(d=>d.T)),us=data.map(d=>d.us_per_token),
  ce=data.map(d=>d.cells),maxU=Math.max(...us)*1.25,maxC=Math.max(...ce)*1.15,
  maxA=Math.max(...data.map(d=>d.flops_attention_equiv));
 const X=t=>P+(Math.log(t)/Math.log(maxT))*(W-P-16),
  Y=u=>H-30-(u/maxU)*(H-56),Y2=v=>H-30-(v/maxC)*(H-56),YA=v=>H-30-(v/maxA)*(H-56);
 x.fillStyle="#fff";x.fillRect(0,0,W,H);x.strokeStyle="#eceef2";x.fillStyle="#6b7280";
 x.font="11px -apple-system,sans-serif";
 for(let i=0;i<=4;i++){const px=P+(i/4)*(W-P-16);x.beginPath();x.moveTo(px,20);x.lineTo(px,H-30);x.stroke()}
 x.strokeStyle="#c2413b";x.setLineDash([6,5]);x.beginPath();let f1=true;
 for(const d of data){const px=X(d.T),py=YA(d.flops_attention_equiv);
  f1?x.moveTo(px,py):x.lineTo(px,py);f1=false}x.stroke();x.setLineDash([]);
 x.strokeStyle="#2547d0";x.lineWidth=2.4;x.beginPath();f1=true;
 for(const d of data){const px=X(d.T),py=Y(d.us_per_token);f1?x.moveTo(px,py):x.lineTo(px,py);f1=false}
 x.stroke();
 x.strokeStyle="#0e8a5f";x.lineWidth=2.4;x.beginPath();f1=true;
 for(const d of data){const px=X(d.T),py=Y2(d.cells);f1?x.moveTo(px,py):x.lineTo(px,py);f1=false}
 x.stroke();x.lineWidth=1;
 for(const d of data){x.fillStyle="#2547d0";x.beginPath();x.arc(X(d.T),Y(d.us_per_token),3.4,0,7);x.fill();
  x.fillStyle="#0e8a5f";x.beginPath();x.arc(X(d.T),Y2(d.cells),3.4,0,7);x.fill()}
 x.fillStyle="#6b7280";
 for(const d of data)x.fillText(d.T.toLocaleString(),X(d.T)-16,H-14);
 x.fillText("stream length (tokens, log scale)",W/2-80,H-2);
 x.fillText("&mu;s/token (blue, flat = constant) · cells (green) · attention O(T²) (dashed red)",P,16)}
$("cost").onclick=async()=>{$("cost").disabled=true;$("cost").textContent="measuring&hellip;";
 try{const sizes=[64,256,1024,2048,4096,8192].map(n=>({n_pairs:n,filler:14}));
  const d=await api("/api/cost",{sizes});drawCC(d)}catch(e){alert(e)}
 $("cost").disabled=false;$("cost").textContent="measure the cost curve"};
/* section 04 */
$("cv").onclick=async()=>{$("cv").disabled=true;
 try{const d=await api("/api/cellview",{name:$("cvn").value.trim()||"key",
  value:$("cvv").value.trim()||"v1",new_value:$("cvnv").value.trim(),seed:(Math.random()*1e6)|0});
  if(d.error){alert(d.error);return}
  const inv={[d.vid]:d.value};inv[d.nid]=d.new_value||d.value;
  $("cvs").innerHTML=`
   <div class="stats" style="display:grid">
    <div class="stat"><b>(${d.addr[0]}, ${d.addr[1]})</b><span>learned address</span></div>
    <div class="stat"><b>${esc(inv[d.answers.before] ?? "—")}</b><span>stored &amp; retrieved before</span></div>
    <div class="stat"><b class="${d.answers.after!==null&&d.answers.after!==d.answers.before?"updv":""}">${esc(d.answers.after!==null?inv[d.answers.after]:"—")}</b><span>after overwrite, same cells</span></div>
   </div>
   <p class="note" style="margin:8px 0 0">key id ${d.kid} &rarr; address on grid scale ${d.scale};
   the write lands as <code>W &larr; &alpha;W + &beta;(v<sub>new</sub> &minus; &alpha;W&kappa;)&kappa;<sup>T</sup>:
   the old association is subtracted out, the new one takes its place &mdash; nothing is appended.</p>`;
  drawCell(d)}catch(e){alert(e)}$("cv").disabled=false};
function drawCell(d){const c=$("cellcv"),x=c.getContext("2d");
 c.width=c.clientWidth*2;c.height=600;x.scale(2,2);const W=c.width/2,H=300;
 x.fillStyle="#fff";x.fillRect(0,0,W,H);const cw=W/3,ch=H/3;
 for(let i=0;i<3;i++)for(let j=0;j<3;j++){
  const phi=d.cells[i][j].phi,z=d.cells[i][j].z;
  const t=Math.min(1,phi/0.7);
  x.fillStyle=`rgba(37,71,208,${(0.06+0.85*t).toFixed(3)})`;
  x.fillRect(j*cw+6,i*ch+6,cw-12,ch-12);
  x.fillStyle=t>0.45?"#fff":"#6b7280";x.font="12px -apple-system,sans-serif";
  x.fillText(`(${z[0]}, ${z[1]})`,j*cw+14,i*ch+24);
  x.font="600 15px -apple-system,sans-serif";
  x.fillText(`phi ${phi.toFixed(3)}`,j*cw+14,i*ch+ch-18)}
 $("cvcap").textContent="the 3x3 neighborhood of the key's address; darker = stronger write/read weight (the bump kernel)."}
window.addEventListener("resize",()=>{});
</script>