-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1659 lines (1574 loc) · 88.5 KB
/
Copy pathindex.html
File metadata and controls
1659 lines (1574 loc) · 88.5 KB
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="An undergraduate-level course on Esper's theory, architecture, and open-ended learning ladder, with original diagrams throughout." />
<title>Understanding Esper — a course</title>
<style>
:root {
--bg: #F1F4F5;
--surface: #FFFFFF;
--surface-2: #E9EDEE;
--ink: #171B1D;
--muted: #56636A;
--faint: #8A969B;
--line: #CBD3D6;
--line-strong: #A9B4B8;
--slow: #2E5A87;
--slow-soft: #DCE6EE;
--slow-ink: #1E3E5F;
--fast: #B4711F;
--fast-soft: #F1E3CE;
--fast-ink: #7A4A10;
--accent-neg: #8C3B32;
--accent-neg-soft: #F1DFDB;
--radius: 3px;
--font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "URW Palladio L", Georgia, serif;
--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
--font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
--content-w: 42rem;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #14181A;
--surface: #1B2023;
--surface-2: #20272A;
--ink: #E7ECED;
--muted: #9AA6AB;
--faint: #6C787D;
--line: #313A3E;
--line-strong: #414D51;
--slow: #7FAAD4;
--slow-soft: #223546;
--slow-ink: #BFDAF2;
--fast: #E3A24E;
--fast-soft: #3B2F1C;
--fast-ink: #F2D6A6;
--accent-neg: #D98E85;
--accent-neg-soft: #3A2320;
}
}
:root[data-theme="dark"] {
--bg: #14181A; --surface: #1B2023; --surface-2: #20272A; --ink: #E7ECED;
--muted: #9AA6AB; --faint: #6C787D; --line: #313A3E; --line-strong: #414D51;
--slow: #7FAAD4; --slow-soft: #223546; --slow-ink: #BFDAF2;
--fast: #E3A24E; --fast-soft: #3B2F1C; --fast-ink: #F2D6A6;
--accent-neg: #D98E85; --accent-neg-soft: #3A2320;
}
:root[data-theme="light"] {
--bg: #F1F4F5; --surface: #FFFFFF; --surface-2: #E9EDEE; --ink: #171B1D;
--muted: #56636A; --faint: #8A969B; --line: #CBD3D6; --line-strong: #A9B4B8;
--slow: #2E5A87; --slow-soft: #DCE6EE; --slow-ink: #1E3E5F;
--fast: #B4711F; --fast-soft: #F1E3CE; --fast-ink: #7A4A10;
--accent-neg: #8C3B32; --accent-neg-soft: #F1DFDB;
}
* { box-sizing: border-box; }
html { color-scheme: light dark; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: var(--font-body);
font-size: 1rem;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
::selection { background: var(--fast-soft); color: var(--ink); }
a { color: var(--slow-ink); text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
a:hover { text-decoration-color: currentColor; }
a:focus-visible, button:focus-visible, summary:focus-visible {
outline: 2px solid var(--fast); outline-offset: 2px;
}
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 600; text-wrap: balance; margin: 0; }
p { margin: 0 0 1rem; max-width: 68ch; }
p:last-child { margin-bottom: 0; }
code, .mono { font-family: var(--font-mono); }
code {
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: var(--radius);
padding: 0.05em 0.35em;
font-size: 0.88em;
word-break: break-word;
}
/* ---------- layout shell ---------- */
.shell { display: grid; grid-template-columns: 272px 1fr; min-height: 100vh; }
.sidebar {
position: sticky; top: 0; height: 100vh; overflow-y: auto;
border-right: 1px solid var(--line);
background: var(--surface);
padding: 1.5rem 1.1rem 3rem;
}
.sidebar-title {
font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.09em;
text-transform: uppercase; color: var(--faint); margin-bottom: 1.1rem;
}
.sidebar-title strong { color: var(--ink); font-weight: 600; }
.toc-module { margin-bottom: 1.15rem; }
.toc-module-link {
display: block; font-family: var(--font-mono); font-size: 0.78rem; font-weight: 600;
letter-spacing: 0.03em; color: var(--ink); text-decoration: none; padding: 0.15rem 0;
border-left: 2px solid transparent; padding-left: 0.6rem; margin-left: -0.62rem;
}
.toc-module-link:hover { color: var(--slow-ink); }
.toc-module-link.active { border-left-color: var(--fast); color: var(--fast-ink); }
.toc-lessons { list-style: none; margin: 0.35rem 0 0; padding: 0 0 0 0.62rem; border-left: 1px solid var(--line); }
.toc-lessons li { margin: 0.05rem 0; }
.toc-lessons a {
display: block; font-size: 0.82rem; color: var(--muted); text-decoration: none;
padding: 0.2rem 0 0.2rem 0.55rem;
}
.toc-lessons a:hover { color: var(--ink); }
.toc-lessons a .loc { font-family: var(--font-mono); color: var(--faint); margin-right: 0.4em; font-size: 0.85em; }
.main { min-width: 0; }
.content { max-width: var(--content-w); margin: 0 auto; padding: 3.2rem 1.5rem 6rem; }
/* ---------- hero / module 0 ---------- */
.hero { padding-bottom: 2.5rem; margin-bottom: 2.5rem; border-bottom: 1px solid var(--line); }
.hero-eyebrow {
font-family: var(--font-mono); font-size: 0.75rem; letter-spacing: 0.12em; text-transform: uppercase;
color: var(--fast-ink); display: flex; align-items: center; gap: 0.55rem; margin-bottom: 0.9rem;
}
.hero h1 { font-size: clamp(2.1rem, 5vw, 2.85rem); line-height: 1.08; margin-bottom: 0.85rem; }
.hero .dek { font-size: 1.15rem; color: var(--muted); max-width: 46ch; margin-bottom: 1.4rem; }
.hero-icon { flex-shrink: 0; }
/* ---------- module bands ---------- */
.module { margin-bottom: 3.4rem; }
.module-band { display: flex; align-items: baseline; gap: 0.85rem; margin-bottom: 0.5rem; }
.module-num {
font-family: var(--font-mono); font-size: 0.95rem; color: var(--faint);
border: 1px solid var(--line-strong); border-radius: var(--radius);
padding: 0.08rem 0.45rem;
}
.module h2 { font-size: 1.7rem; }
.module-dek { color: var(--muted); font-size: 1.02rem; margin: 0.5rem 0 2rem; max-width: 58ch; }
.module-rule { height: 1px; background: linear-gradient(to right, var(--line-strong), transparent 70%); margin-bottom: 2rem; }
/* ---------- lessons ---------- */
.lesson { padding: 1.7rem 0; border-top: 1px solid var(--line); }
.module > .lesson:first-of-type { border-top: none; padding-top: 0; }
.lesson-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.6rem 0.7rem; margin-bottom: 0.7rem; }
.lesson-loc { font-family: var(--font-mono); font-size: 0.85rem; color: var(--faint); }
.lesson h3 { font-size: 1.22rem; display: inline; }
.tags { display: flex; gap: 0.4rem; margin-left: auto; flex-wrap: wrap; }
.tag {
font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.06em; text-transform: uppercase;
padding: 0.12rem 0.42rem; border-radius: var(--radius); white-space: nowrap; font-weight: 600;
}
.tag-slow { background: var(--slow-soft); color: var(--slow-ink); }
.tag-fast { background: var(--fast-soft); color: var(--fast-ink); }
.tag-neutral { background: var(--surface-2); color: var(--muted); border: 1px solid var(--line); }
.lesson-body :is(ul, ol) { margin: 0 0 1rem; padding-left: 1.3rem; max-width: 66ch; }
.lesson-body li { margin-bottom: 0.4rem; }
dfn { font-style: normal; font-weight: 600; color: var(--ink); border-bottom: 1px dotted var(--faint); }
/* ---------- callouts ---------- */
.callout {
border: 1px solid var(--line); border-left: 3px solid var(--line-strong);
border-radius: var(--radius); background: var(--surface); padding: 0.95rem 1.1rem;
margin: 1.1rem 0; max-width: 66ch;
}
.callout-label {
font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase;
font-weight: 700; display: block; margin-bottom: 0.45rem;
}
.callout p { margin-bottom: 0.4rem; font-size: 0.95rem; }
.callout p:last-child { margin-bottom: 0; }
.callout-def { border-left-color: var(--slow); }
.callout-def .callout-label { color: var(--slow-ink); }
.callout-measured { border-left-color: var(--fast); }
.callout-measured .callout-label { color: var(--fast-ink); }
.callout-neg { border-left-color: var(--accent-neg); background: var(--accent-neg-soft); }
.callout-neg .callout-label { color: var(--accent-neg); }
.stat-row { display: flex; gap: 1.6rem; flex-wrap: wrap; margin-top: 0.3rem; }
.stat { font-family: var(--font-mono); }
.stat .n { font-size: 1.3rem; font-weight: 700; font-variant-numeric: tabular-nums; display: block; }
.stat .l { font-size: 0.72rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
/* ---------- diagram frames ---------- */
.diagram {
margin: 1.3rem 0 0.6rem; border: 1px solid var(--line); border-radius: var(--radius);
background-color: var(--surface);
background-image:
linear-gradient(var(--line) 1px, transparent 1px),
linear-gradient(90deg, var(--line) 1px, transparent 1px);
background-size: 22px 22px;
background-position: -1px -1px;
background-blend-mode: normal;
padding: 1.1rem 1rem 0.9rem;
overflow-x: auto;
}
.diagram-inner { min-width: 260px; }
.diagram svg { display: block; margin: 0 auto; max-width: 100%; height: auto; }
.diagram pre.mermaid { margin: 0; background: transparent; }
.fig-caption {
font-family: var(--font-mono); font-size: 0.72rem; color: var(--muted);
text-align: center; margin-top: 0.55rem; letter-spacing: 0.01em;
}
/* ---------- tables ---------- */
.table-wrap { overflow-x: auto; margin: 1.1rem 0; }
table { border-collapse: collapse; width: 100%; min-width: 480px; font-size: 0.92rem; }
th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--line); vertical-align: top; }
thead th {
font-family: var(--font-mono); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
color: var(--muted); border-bottom: 1px solid var(--line-strong);
}
tbody tr:hover { background: var(--surface-2); }
/* ---------- glossary ---------- */
.glossary dt { font-family: var(--font-mono); font-weight: 700; margin-top: 0.9rem; }
.glossary dd { margin: 0.15rem 0 0; color: var(--muted); max-width: 60ch; }
.values-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.values-list li { display: grid; grid-template-columns: 1.6rem 1fr; gap: 0.75rem; }
.values-list .vn { font-family: var(--font-mono); color: var(--fast-ink); font-weight: 700; }
footer.colophon {
margin-top: 3.5rem; padding-top: 1.6rem; border-top: 1px solid var(--line);
font-size: 0.85rem; color: var(--muted);
}
footer.colophon ul { padding-left: 1.2rem; }
footer.colophon li { margin-bottom: 0.3rem; }
/* ---------- mobile ---------- */
@media (max-width: 860px) {
.shell { display: block; }
.sidebar {
position: sticky; top: 0; height: auto; max-height: none; overflow: visible;
display: flex; gap: 1rem; align-items: center; padding: 0.7rem 1rem;
z-index: 5; overflow-x: auto; white-space: nowrap;
}
.sidebar-title { margin: 0; flex-shrink: 0; }
.toc-module { margin-bottom: 0; flex-shrink: 0; }
.toc-lessons { display: none; }
.content { padding: 2.2rem 1.2rem 4rem; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
@media (prefers-reduced-motion: no-preference) {
html { scroll-behavior: smooth; }
}
</style>
</head>
<body>
<div class="shell">
<nav class="sidebar" aria-label="Course contents">
<div class="sidebar-title"><strong>Understanding Esper</strong> · a course</div>
<div class="toc-module">
<a class="toc-module-link" href="#m0" data-mod="m0">Start here</a>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m1" data-mod="m1">1 · Learning as memory</a>
<ul class="toc-lessons">
<li><a href="#l1-1"><span class="loc">1.1</span>The one atom</a></li>
<li><a href="#l1-2"><span class="loc">1.2</span>Nested systems</a></li>
<li><a href="#l1-3"><span class="loc">1.3</span>Optimizers as memory</a></li>
<li><a href="#l1-4"><span class="loc">1.4</span>Continuum memory</a></li>
<li><a href="#l1-5"><span class="loc">1.5</span>Self-modifying + HOPE</a></li>
<li><a href="#l1-6"><span class="loc">1.6</span>Revisited terms</a></li>
</ul>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m2" data-mod="m2">2 · Evolution strategies</a>
<ul class="toc-lessons">
<li><a href="#l2-1"><span class="loc">2.1</span>No backprop, by rule</a></li>
<li><a href="#l2-2"><span class="loc">2.2</span>Antithetic sampling</a></li>
<li><a href="#l2-3"><span class="loc">2.3</span>Anneal: wide then sharp</a></li>
<li><a href="#l2-4"><span class="loc">2.4</span>Two timescales, meta-learned</a></li>
</ul>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m3" data-mod="m3">3 · Core architecture</a>
<ul class="toc-lessons">
<li><a href="#l3-1"><span class="loc">3.1</span>The arena</a></li>
<li><a href="#l3-2"><span class="loc">3.2</span>fast / slow, mapped</a></li>
<li><a href="#l3-3"><span class="loc">3.3</span>Domain & Memory</a></li>
<li><a href="#l3-4"><span class="loc">3.4</span>The first operator</a></li>
<li><a href="#l3-5"><span class="loc">3.5</span>The uncheatable metric</a></li>
</ul>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m4" data-mod="m4">4 · The memory zoo</a>
<ul class="toc-lessons">
<li><a href="#l4-1"><span class="loc">4.1</span>MLP: first emergence</a></li>
<li><a href="#l4-2"><span class="loc">4.2</span>Attention gather</a></li>
<li><a href="#l4-3"><span class="loc">4.3</span>The composition pattern</a></li>
<li><a href="#l4-4"><span class="loc">4.4</span>Self-modifying memories</a></li>
<li><a href="#l4-5"><span class="loc">4.5</span>2-D grid self-mod</a></li>
<li><a href="#l4-6"><span class="loc">4.6</span>Shape as content</a></li>
<li><a href="#l4-7"><span class="loc">4.7</span>Content-addressed memory</a></li>
<li><a href="#l4-8"><span class="loc">4.8</span>Honest scorecard</a></li>
</ul>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m5" data-mod="m5">5 · Open-ended mastery</a>
<ul class="toc-lessons">
<li><a href="#l5-1"><span class="loc">5.1</span>The last hand-out</a></li>
<li><a href="#l5-2"><span class="loc">5.2</span>A reward-free world</a></li>
<li><a href="#l5-3"><span class="loc">5.3</span>Novelty search</a></li>
<li><a href="#l5-4"><span class="loc">5.4</span>MAP-Elites repertoires</a></li>
<li><a href="#l5-5"><span class="loc">5.5</span>Empowerment</a></li>
<li><a href="#l5-6"><span class="loc">5.6</span>World model + LP</a></li>
<li><a href="#l5-7"><span class="loc">5.7</span>Convergence, tested</a></li>
<li><a href="#l5-8"><span class="loc">5.8</span>ACCEL curriculum</a></li>
</ul>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m6" data-mod="m6">6 · Cross-world transfer</a>
<ul class="toc-lessons">
<li><a href="#l6-1"><span class="loc">6.1</span>The pivot</a></li>
<li><a href="#l6-2"><span class="loc">6.2</span>Walls: world 2</a></li>
<li><a href="#l6-3"><span class="loc">6.3</span>What carries</a></li>
<li><a href="#l6-4"><span class="loc">6.4</span>What's next</a></li>
</ul>
</div>
<div class="toc-module">
<a class="toc-module-link" href="#m7" data-mod="m7">7 · Wrap-up</a>
<ul class="toc-lessons">
<li><a href="#l7-1"><span class="loc">7.1</span>The six values</a></li>
<li><a href="#l7-2"><span class="loc">7.2</span>Glossary</a></li>
<li><a href="#l7-3"><span class="loc">7.3</span>Where to go deeper</a></li>
</ul>
</div>
</nav>
<main class="main">
<div class="content">
<!-- ============ MODULE 0 ============ -->
<section id="m0" class="hero">
<div class="hero-eyebrow">
<svg class="hero-icon" width="26" height="26" viewBox="0 0 26 26" fill="none" aria-hidden="true">
<rect x="1" y="1" width="24" height="24" rx="2" stroke="var(--fast)" stroke-width="1.4"/>
<rect x="5" y="5" width="16" height="16" rx="1.5" stroke="var(--slow)" stroke-width="1.4"/>
<rect x="9" y="9" width="8" height="8" rx="1" fill="var(--fast)"/>
</svg>
A course · undergraduate level · 7 modules
</div>
<h1>Understanding Esper</h1>
<p class="dek">
Esper is a bare-metal reasoning engine that learns the way a living system adapts:
no backpropagation, no hand-installed rules, two clocks running at once — one that
adapts in seconds to what's in front of it, one that changes slowly across everything
it has ever seen. This course builds that idea up from a single equation to the
engine's current research frontier, one short lesson at a time.
</p>
<p style="color:var(--muted); font-size:0.92rem;">
Each lesson is numbered <code>module.lesson</code> and assumes only what came before it —
skim the sidebar to jump around, or read straight through. Colored tags mark ideas that
belong to Esper's two timescales:
<span class="tag tag-slow" style="margin:0 0.3em;">slow</span>
persistent, meta-learned, changes rarely, and
<span class="tag tag-fast" style="margin:0 0.3em;">fast</span>
in-context, adapted per problem, changes constantly. That duality is the spine of
everything below.
</p>
</section>
<!-- ============ MODULE 1 ============ -->
<section id="m1" class="module">
<div class="module-band">
<span class="module-num">01</span>
<h2>Learning as memory</h2>
</div>
<p class="module-dek">
Esper's architecture is a direct application of a 2025 theory paper, <em>Nested
Learning: The Illusion of Deep Learning Architecture</em> (Behrouz, Razaviyayn, Zhong,
Mirrokni — Google Research). Its central claim: a deep model isn't one architecture
trained by one optimizer — it's a stack of optimization problems running at different
speeds. This module distills that theory before any of it touches code.
</p>
<div class="module-rule"></div>
<div class="lesson" id="l1-1">
<div class="lesson-head">
<span class="lesson-loc">1.1</span>
<h3>The one atom: associative memory</h3>
</div>
<div class="lesson-body">
<p>
Everything in this theory reduces to one operator. An <dfn>associative memory</dfn>
<code>M</code> maps a set of keys <code>K</code> to values <code>V</code>, found by
minimizing how badly it maps one onto the other:
<code>M* = argmin_M L̂(M(K); V)</code>. Keys and values don't have to be
tokens — they can be gradients, sub-sequences, error signals, anything with a
measurable mapping quality.
</p>
<div class="callout callout-def">
<span class="callout-label">Definition</span>
<p>"Memory is a neural update caused by an input; learning is the process of
acquiring effective memory." — Behrouz et al., §3.1</p>
</div>
<p>
<dfn>Memorization</dfn> is forming any mapping. <dfn>Learning</dfn> is forming one
that generalizes. That distinction — memorizing versus learning an effective
mapping — is the exact line Esper draws between fitting a task's examples and
solving the held-out one (Module 3.5).
</p>
</div>
</div>
<div class="lesson" id="l1-2">
<div class="lesson-head">
<span class="lesson-loc">1.2</span>
<h3>Nested systems</h3>
</div>
<div class="lesson-body">
<p>
A <dfn>nested system</dfn> is an ordered stack of levels, each one an optimization
problem minimizing its own objective over its own parameters and its own slice of
context. The ordering isn't depth in the usual sense — it's <strong>update
frequency</strong>. A higher level updates less often than the one below it.
</p>
<p>
When every level in the stack happens to be an associative memory (1.1), the paper
calls the whole thing an <dfn>NSAM</dfn> — a nested system of associative memories.
Its claim is that modern architectures, plus the optimizers that train them, are
already instances of this pattern; they just don't advertise it as one.
</p>
<div class="diagram">
<div class="diagram-inner">
<pre class="mermaid">
graph TD
A["Level 1 — highest frequency<br/>within-sequence attention"] --> B["Level 2<br/>momentum / optimizer state"]
B --> C["Level 3<br/>within-task weight updates"]
C --> D["Level K — lowest frequency<br/>pretraining, whole dataset as context"]
D -. "knowledge transfer: init · backprop · weight generation" .-> A
</pre>
</div>
<div class="fig-caption">Fig 1.2 — a nested system, ordered by update frequency, not layer depth</div>
</div>
<p>
Two design choices define any one module in this frame: <strong>(1)</strong> what
optimization problems it runs and at what frequencies, and <strong>(2)</strong> how
knowledge moves between its levels — directly, by backprop, by meta-learned
initialization, or by generating one level's weights from another.
</p>
</div>
</div>
<div class="lesson" id="l1-3">
<div class="lesson-head">
<span class="lesson-loc">1.3</span>
<h3>Optimizers are themselves memories</h3>
</div>
<div class="lesson-body">
<p>
This is the paper's sharpest reframe. Training a network by backprop is a
<em>compression</em> process — each layer is an associative memory mapping its
input to its local error signal. And the momentum term in SGD isn't a bookkeeping
trick; it's an associative memory that compresses <em>past gradients</em> into its
own state. Gradient descent with momentum is already a 2-level nested system: the
inner level learns momentum, the outer level uses it. Adam, RMSProp, AdaGrad,
Shampoo are all instances of the same pattern with a richer inner memory.
</p>
<p>
Standard momentum is a weak low-pass filter — at β = 0.9, the last ~43 gradients
hold over 99% of the weight — which is why it forgets the gradient subspace of an
earlier, orthogonal task. Every mitigation for catastrophic forgetting later in
this course is, underneath, a fix to this same forgetting mechanism.
</p>
</div>
</div>
<div class="lesson" id="l1-4">
<div class="lesson-head">
<span class="lesson-loc">1.4</span>
<h3>The Continuum Memory System</h3>
<span class="tags"><span class="tag tag-neutral">north star</span></span>
</div>
<div class="lesson-body">
<p>
Drop the binary of "short-term vs. long-term memory." Replace it with a
<dfn>Continuum Memory System</dfn> (CMS): a chain of memory blocks, each updated at
its own frequency <code>C^(ℓ)</code>. High-frequency blocks behave like short-term,
fast adaptation; low-frequency blocks behave like persistent, slowly-won knowledge.
A Transformer's MLP block is just the special case of one block, one frequency.
</p>
<div class="diagram">
<div class="diagram-inner">
<svg viewBox="0 0 560 150" role="img" aria-label="frequency spectrum of CMS blocks">
<defs>
<linearGradient id="freqGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="var(--fast)"/>
<stop offset="100%" stop-color="var(--slow)"/>
</linearGradient>
</defs>
<line x1="30" y1="120" x2="530" y2="120" stroke="var(--line-strong)" stroke-width="1.5"/>
<rect x="30" y="118" width="500" height="4" fill="url(#freqGrad)" opacity="0.35"/>
<text x="30" y="140" font-family="var(--font-mono)" font-size="11" fill="var(--fast-ink)">fast · high frequency</text>
<text x="530" y="140" text-anchor="end" font-family="var(--font-mono)" font-size="11" fill="var(--slow-ink)">slow · low frequency</text>
<g font-family="var(--font-mono)" font-size="11" fill="var(--ink)">
<rect x="55" y="70" width="26" height="48" rx="2" fill="var(--fast-soft)" stroke="var(--fast)"/>
<text x="68" y="65" text-anchor="middle">C¹</text>
<rect x="140" y="55" width="26" height="63" rx="2" fill="var(--fast-soft)" stroke="var(--fast)" opacity="0.85"/>
<text x="153" y="50" text-anchor="middle">C²</text>
<rect x="260" y="40" width="26" height="78" rx="2" fill="var(--surface-2)" stroke="var(--line-strong)"/>
<text x="273" y="35" text-anchor="middle">C³</text>
<rect x="380" y="25" width="26" height="93" rx="2" fill="var(--slow-soft)" stroke="var(--slow)" opacity="0.85"/>
<text x="393" y="20" text-anchor="middle">C⁴</text>
<rect x="465" y="12" width="26" height="106" rx="2" fill="var(--slow-soft)" stroke="var(--slow)"/>
<text x="478" y="7" text-anchor="middle">C⁵</text>
</g>
</svg>
</div>
<div class="fig-caption">Fig 1.4 — CMS as a spectrum of blocks, not a two-tier cache</div>
</div>
<p>
The payoff is resistance to forgetting: when one block gets overwritten by new
context, older knowledge still lives undisturbed in the other-frequency blocks, and
can be recovered through cross-level transfer. Blocks only compute on their own
schedule, so updates stay cheap and parallelizable.
</p>
</div>
</div>
<div class="lesson" id="l1-5">
<div class="lesson-head">
<span class="lesson-loc">1.5</span>
<h3>Self-modifying memory, and HOPE</h3>
</div>
<div class="lesson-body">
<p>
A standard Transformer's key/query/value projections are fixed after training —
whatever contextualization happens, it's bounded by that first, frozen level. A
<dfn>self-modifying memory</dfn> breaks that: it generates its <em>own</em> keys,
values, learning rate <code>η</code>, and retention gate <code>α</code>, per input,
and optimizes itself against an internal objective. It is, in a real sense,
controlling its own learning process.
</p>
<div class="callout callout-def">
<span class="callout-label">HOPE</span>
<p>Self-modifying Titans <strong>followed by</strong> a CMS chain (1.4): a small,
richly-adaptive block handles fast, in-context change; a multi-frequency stack
behind it holds persistent knowledge. Small capacity + rich rule, feeding large
capacity + simple rule.</p>
</div>
</div>
</div>
<div class="lesson" id="l1-6">
<div class="lesson-head">
<span class="lesson-loc">1.6</span>
<h3>Terms this reframes</h3>
</div>
<div class="lesson-body">
<ul>
<li><strong>In-context learning</strong> isn't an emergent surprise — it's the
direct consequence of having multiple frequency levels at all. Any level adapting
to its context is doing ICL, by definition.</li>
<li><strong>Pre-training</strong> is just the lowest-frequency level: ICL where the
context happens to be the entire dataset.</li>
<li><strong>Test-time training</strong> is parametric in-context learning whose
acquired knowledge vanishes the moment the context is removed.</li>
<li>There is <strong>no train/test boundary</strong> inside a neural learning
module — only two states: receiving input, or sitting isolated.</li>
</ul>
<p>
One more consequence worth carrying forward: momentum state, optimizer state, RNN
hidden state — these are all knowledge stores too, not just the weights that
backprop touches. Module 3 will make the same move for Esper: its "parameters"
include a fast-changing part and a slow-changing part, and both are learned.
</p>
</div>
</div>
</section>
<!-- ============ MODULE 2 ============ -->
<section id="m2" class="module">
<div class="module-band">
<span class="module-num">02</span>
<h2>Evolution strategies</h2>
</div>
<p class="module-dek">
Nested Learning describes optimizers as memories in the abstract. Esper needs an actual
one — and it can't be backprop. This module covers the mechanism that fits every memory
in the rest of the course: a derivative-free Evolution Strategy (ES).
</p>
<div class="module-rule"></div>
<div class="lesson" id="l2-1">
<div class="lesson-head">
<span class="lesson-loc">2.1</span>
<h3>Why not backprop</h3>
</div>
<div class="lesson-body">
<p>
Esper is built under a hard constraint: zero external ML libraries, and no autodiff
framework in the runtime path. That's not an implementation detail, it's a
methodological stance — nothing about <em>how the engine learns</em> should be
inherited from a framework unexamined. So gradients aren't computed by
backpropagating through a computation graph; they're <em>estimated</em> by
perturbing parameters and observing how a scalar fitness responds.
</p>
</div>
</div>
<div class="lesson" id="l2-2">
<div class="lesson-head">
<span class="lesson-loc">2.2</span>
<h3>Antithetic sampling</h3>
</div>
<div class="lesson-body">
<p>
One ES step: draw real Gaussian noise <code>ε</code>, evaluate the fitness function
<code>F</code> at two mirrored points, <code>w + σε</code> and <code>w − σε</code>,
and combine the two scores into a gradient estimate. Because the pair is symmetric
around <code>w</code>, the noise on either side cancels in expectation and what's
left points toward the direction that actually improved fitness.
</p>
<div class="diagram">
<div class="diagram-inner">
<svg viewBox="0 0 560 190" role="img" aria-label="antithetic sampling on a fitness landscape">
<path d="M 30 150 C 120 40, 220 170, 300 90 S 460 30, 530 110" fill="none" stroke="var(--line-strong)" stroke-width="2"/>
<line x1="240" y1="0" x2="240" y2="190" stroke="var(--line)" stroke-dasharray="3 4"/>
<circle cx="240" cy="127" r="4.5" fill="var(--ink)"/>
<text x="248" y="122" font-family="var(--font-mono)" font-size="11" fill="var(--ink)">w</text>
<line x1="175" y1="0" x2="175" y2="190" stroke="var(--fast)" stroke-dasharray="3 4" opacity="0.6"/>
<circle cx="175" cy="72" r="4.5" fill="var(--fast)"/>
<text x="150" y="60" font-family="var(--font-mono)" font-size="11" fill="var(--fast-ink)">w − σε</text>
<line x1="305" y1="0" x2="305" y2="190" stroke="var(--slow)" stroke-dasharray="3 4" opacity="0.6"/>
<circle cx="305" cy="88" r="4.5" fill="var(--slow)"/>
<text x="313" y="80" font-family="var(--font-mono)" font-size="11" fill="var(--slow-ink)">w + σε</text>
<text x="30" y="20" font-family="var(--font-mono)" font-size="11" fill="var(--muted)">F(w) — fitness</text>
</svg>
</div>
<div class="fig-caption">Fig 2.2 — a mirrored pair straddling the current parameter, on a 1-D slice of fitness</div>
</div>
<div class="diagram">
<div class="diagram-inner">
<pre class="mermaid">
graph LR
N["draw noise ε ~ N(0,1)"] --> P["w + σ·scale·ε"]
N --> Q["w − σ·scale·ε"]
P --> FP["F(w+σε)"]
Q --> FM["F(w−σε)"]
FP --> G["grad += (F+ − F−) · ε"]
FM --> G
G --> U["w += (α / 2Nσ) · scale · grad"]
</pre>
</div>
<div class="fig-caption">Fig 2.2b — one antithetic ES iteration, averaged over N pairs</div>
</div>
<p>
<code>scale</code> is a per-parameter preconditioner — different parameter groups
(say, geometry versus colour) can need different step sizes, so one shared
<code>σ</code> gets rescaled per group rather than forcing a single compromise.
</p>
</div>
</div>
<div class="lesson" id="l2-3">
<div class="lesson-head">
<span class="lesson-loc">2.3</span>
<h3>Anneal: explore wide, then settle sharp</h3>
</div>
<div class="lesson-body">
<p>
A single fixed <code>σ</code> can't do both jobs a fit needs. Early on, the search
needs to be wide enough to discover a qualitatively different region of parameter
space (a large layout change like a transpose). Late in the fit, it needs to be
narrow enough to settle onto an exact value without noise pushing it back off. Esper
anneals both <code>σ</code> and the step size <code>α</code> across the fit — wide
and fast at the start, small and cautious by the end — over a few thousand
iterations.
</p>
<div class="diagram">
<div class="diagram-inner">
<svg viewBox="0 0 500 130" role="img" aria-label="sigma decay curve">
<path d="M 40 20 C 120 40, 180 90, 460 108" fill="none" stroke="var(--fast)" stroke-width="2.5"/>
<line x1="40" y1="115" x2="460" y2="115" stroke="var(--line-strong)"/>
<line x1="40" y1="10" x2="40" y2="115" stroke="var(--line-strong)"/>
<text x="40" y="128" font-family="var(--font-mono)" font-size="10" fill="var(--muted)">iter 0</text>
<text x="460" y="128" text-anchor="end" font-family="var(--font-mono)" font-size="10" fill="var(--muted)">iter ~4000</text>
<text x="10" y="24" font-family="var(--font-mono)" font-size="10" fill="var(--fast-ink)">σ=0.5</text>
<text x="10" y="115" font-family="var(--font-mono)" font-size="10" fill="var(--fast-ink)">σ=0.01</text>
</svg>
</div>
<div class="fig-caption">Fig 2.3 — the annealed sigma schedule: explore, then settle onto exact values</div>
</div>
</div>
</div>
<div class="lesson" id="l2-4">
<div class="lesson-head">
<span class="lesson-loc">2.4</span>
<h3>Two timescales, and the slow one is meta-learned</h3>
<span class="tags"><span class="tag tag-slow">slow</span><span class="tag tag-fast">fast</span></span>
</div>
<div class="lesson-body">
<p>
Here the ES core stops being single-task. An outer, low-frequency loop — a Reptile
meta-loop — runs across <em>many</em> tasks: for each one, it fits <code>fast</code>
in-context starting from the current <code>slow</code>, then nudges
<code>slow</code> a small step toward wherever <code>fast</code> ended up:
<code>slow += META_LR · (fast − slow)</code>.
</p>
<div class="diagram">
<div class="diagram-inner">
<pre class="mermaid">
graph TD
S["slow — the prior<br/>(persists across tasks)"] -->|"fit_operator, anchored to slow"| F["fast — per-task fit<br/>(in-context, from demos)"]
F -->|"reptile: slow += META_LR·(fast − slow)"| S
</pre>
</div>
<div class="fig-caption">Fig 2.4 — the outer Reptile loop turning a fixed prior into a meta-learned one</div>
</div>
<p>
This is the Nested-Learning idea from 1.2, made concrete: two optimization problems
at two frequencies, with knowledge transferred between them by initialization —
exactly the MAML-style transfer the paper names. A fresh, in-family task can now be
fit at a narrow, cheap budget where a cold (identity) prior simply fails: warm start
plus a cheap local fit beats cold start plus a wide search, but only because the
prior has already absorbed the family's shape.
</p>
</div>
</div>
</section>
<!-- ============ MODULE 3 ============ -->
<section id="m3" class="module">
<div class="module-band">
<span class="module-num">03</span>
<h2>Esper's core architecture</h2>
</div>
<p class="module-dek">
With the theory (Module 1) and the optimizer (Module 2) in hand, this module opens the
engine itself: how it stores a task, what its two weight sets actually are, and the
seam that lets new memory types be added without touching the learning core.
</p>
<div class="module-rule"></div>
<div class="lesson" id="l3-1">
<div class="lesson-head">
<span class="lesson-loc">3.1</span>
<h3>The arena: memory with no allocator in the hot loop</h3>
</div>
<div class="lesson-body">
<p>
Esper is pure Mojo, bare metal, no dynamic allocation inside a hot loop. Its arena
(<code>HopeArena</code>) is a move-only bump-pointer allocator: a contiguous block
of memory where allocation is "wherever the pointer currently is," and the pointer
only ever moves forward. Nodes placed into it (<code>HopeNode</code>) are kept
strictly POD — raw pointers and integers, no owning members — specifically so they
can be moved into bump-allocated memory without a per-node heap allocation.
</p>
<div class="diagram">
<div class="diagram-inner">
<svg viewBox="0 0 560 120" role="img" aria-label="bump allocator arena layout">
<rect x="20" y="30" width="520" height="46" fill="var(--surface-2)" stroke="var(--line-strong)" rx="2"/>
<rect x="20" y="30" width="120" height="46" fill="var(--slow-soft)" stroke="var(--slow)" rx="2"/>
<text x="80" y="58" text-anchor="middle" font-family="var(--font-mono)" font-size="11" fill="var(--slow-ink)">HopeNode A</text>
<rect x="140" y="30" width="150" height="46" fill="var(--fast-soft)" stroke="var(--fast)" rx="2"/>
<text x="215" y="58" text-anchor="middle" font-family="var(--font-mono)" font-size="11" fill="var(--fast-ink)">HopeNode B</text>
<rect x="290" y="30" width="95" height="46" fill="var(--slow-soft)" stroke="var(--slow)" rx="2"/>
<text x="337" y="58" text-anchor="middle" font-family="var(--font-mono)" font-size="11" fill="var(--slow-ink)">HopeNode C</text>
<line x1="385" y1="20" x2="385" y2="86" stroke="var(--ink)" stroke-width="2"/>
<polygon points="385,14 379,24 391,24" fill="var(--ink)"/>
<text x="385" y="12" text-anchor="middle" font-family="var(--font-mono)" font-size="10" fill="var(--ink)">bump pointer</text>
<text x="465" y="58" text-anchor="middle" font-family="var(--font-mono)" font-size="11" fill="var(--faint)">unused</text>
</svg>
</div>
<div class="fig-caption">Fig 3.1 — the arena: allocation is a pointer bump, never a free list</div>
</div>
</div>
</div>
<div class="lesson" id="l3-2">
<div class="lesson-head">
<span class="lesson-loc">3.2</span>
<h3>fast and slow, mapped onto HOPE</h3>
<span class="tags"><span class="tag tag-slow">slow</span><span class="tag tag-fast">fast</span></span>
</div>
<div class="lesson-body">
<p>
Every <code>HopeNode</code> carries two weight slices: <code>slow</code> and
<code>fast</code>. This is Module 1's two-timescale idea, given a name in code.
<code>fast</code> is fit fresh in-context on one task's demonstration pairs;
<code>slow</code> is the meta-learned prior it's anchored to, updated only by the
outer Reptile loop (2.4) across many tasks.
</p>
<div class="table-wrap">
<table>
<thead><tr><th>Paper concept</th><th>Esper realization</th></tr></thead>
<tbody>
<tr><td>Slow (low-frequency) level = meta-learned prior / init</td><td><code>HopeNode.slow</code> + the L2 anchor inside <code>fitness</code></td></tr>
<tr><td>Fast (high-frequency) memory adapted in-context</td><td><code>HopeNode.fast</code>, fit per-task</td></tr>
<tr><td>Optimizer as a derivative-free learning rule</td><td>antithetic-sampling ES (<code>evolve_fast_weights</code>)</td></tr>
<tr><td>"Learning is acquiring effective memory"</td><td>the engine must learn the grid→grid transform — never be handed a DSL</td></tr>
<tr><td>Continuum Memory System</td><td>north star: a multi-frequency memory stack (persistent slow weights, Module 6.4)</td></tr>
<tr><td>Self-modifying memory</td><td>the fully-emergent end state once "training wheels" come off (Module 4.4)</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="lesson" id="l3-3">
<div class="lesson-head">
<span class="lesson-loc">3.3</span>
<h3>The seams: Domain and Memory</h3>
</div>
<div class="lesson-body">
<p>
Two traits keep the ES core generic. A <dfn>Domain</dfn> defines what a problem
looks like — an example type, a distance metric, a score — without saying anything
about grids specifically (a grid domain and a 1-D sequence domain both conform, with
zero change to the ES). A <dfn>Memory</dfn> defines what gets fit: a parameter
count, a seed, and an <code>apply</code> function from weights + input to output.
</p>
<div class="diagram">
<div class="diagram-inner">
<pre class="mermaid">
graph TD
Dom["Domain trait<br/>Example type · distance · score"] -->|associated type| Mem["Memory trait<br/>param_dim · seed · apply(weights, input) → output"]
Mem --> Fit["ES core: fitness / evolve_fast_weights / fit_operator"]
Fit --> Score["held-out score, via Domain.distance"]
</pre>
</div>
<div class="fig-caption">Fig 3.3 — the seam the ES core reaches every problem through</div>
</div>
<p>
Crucially, <strong>there is no runtime memory-selector</strong> — which memory to
use is a compile-time choice, not a dispatch decision the engine makes at runtime.
A runtime selector over hand-written memories would itself be a symbolic DSL by
another name, which is exactly what the project's first value forbids (Module 7.1).
New memory types are added additively, and each is measured only on the subset of
problems it can express.
</p>
</div>
</div>
<div class="lesson" id="l3-4">
<div class="lesson-head">
<span class="lesson-loc">3.4</span>
<h3>Worked example: the structured operator</h3>
</div>
<div class="lesson-body">
<p>
The first working <code>Memory</code> is a hand-structured one, useful precisely
because it's simple enough to read end-to-end. Its 16 parameters are a 6-value
centered affine transform (the geometry: flips, transpose) plus a 10-entry colour
lookup table. It runs <strong>colour, then gather</strong>: each of the four corner
input cells is mapped through the colour table <em>before</em> being blended by the
geometry, which decouples the colour fit from the geometry's precision. The gather
is smooth (bilinear) so the ES always has a usable gradient signal, yet lands
exactly on the target at integer parameter values.
</p>
<div class="callout callout-def">
<span class="callout-label">Why this memory is later retired</span>
<p>Its 16 hand-picked parameters can only express affine geometry plus a global
recolor. Module 4 replaces it, piece by piece, with memories that <em>learn</em> the
same behavior — and more — with nothing hand-installed.</p>
</div>
</div>
</div>
<div class="lesson" id="l3-5">
<div class="lesson-head">
<span class="lesson-loc">3.5</span>
<h3>The metric that can't be cheated</h3>
</div>
<div class="lesson-body">
<p>
Every memory is fit on a task's <em>demonstration</em> pairs, then scored on an
<em>unseen</em> test pair from the same task. Fitting the demos well proves nothing
by itself — a memory with enough free parameters can memorize any finite set of
examples. Generalizing to the held-out pair is the only claim that a genuine
transformation, not a lookup table, was found.
</p>
<div class="callout callout-neg">
<span class="callout-label">The cold-fit bar</span>
<p>If a memory only clears this bar via per-task hand-staging, mid-fit parameter
boosts, or bespoke tuning, the project calls that <strong>"stone soup"</strong>: the
reasoning lived in the human who staged it, not in the model. Such results are
recorded as documented negative results, never as milestones.</p>
</div>
</div>
</div>
</section>
<!-- ============ MODULE 4 ============ -->
<section id="m4" class="module">
<div class="module-band">
<span class="module-num">04</span>
<h2>The emergent memory zoo</h2>
</div>
<p class="module-dek">
This is the project's longest-running thread: replacing every hand-coded piece of the
structured operator (3.4) with something the engine learns for itself, one training
wheel at a time, each new memory measured honestly on what it can and can't express.
</p>
<div class="module-rule"></div>
<div class="diagram">
<div class="diagram-inner">
<pre class="mermaid">
graph LR
OP["Structured operator<br/>hand-coded affine + LUT"] --> MLP["MLPMemory<br/>emergent colour, no LUT"]
MLP --> ATT["AttnGather<br/>emergent geometry"]
ATT --> COMP["Composed memories<br/>commuting factors"]
COMP --> SM["Self-modifying memories<br/>write rule, not ES-searched"]
SM --> CF["Content-addressed memory<br/>copy · move · draw"]
</pre>
</div>
<div class="fig-caption">Fig 4.0 — the zoo's evolution: each stage removes one hand-installed piece</div>
</div>
<div class="lesson" id="l4-1">
<div class="lesson-head">
<span class="lesson-loc">4.1</span>
<h3>First emergence: a per-cell MLP</h3>
<span class="tags"><span class="tag tag-fast">fast</span></span>
</div>
<div class="lesson-body">
<p>
The first training wheel to come off is the colour lookup table. <code>MLPMemory</code>
is a tiny per-cell <code>1→H→1</code> tanh network, fit the same way as everything
else — by ES, on the demos. It learns to recolor a grid to held-out 1.0 with no
lookup table hand-installed: the mapping itself is discovered, not looked up.
</p>
</div>
</div>
<div class="lesson" id="l4-2">
<div class="lesson-head">
<span class="lesson-loc">4.2</span>
<h3>Emergent geometry: attention as a gather</h3>
</div>
<div class="lesson-body">
<p>
<code>AttnGatherMemory</code> replaces the hand-coded affine transform with a
7-parameter learned position-attention gather: a 2×2 coordinate projection plus a
temperature, softmax-weighted over a small window. With integer-valued projections
it reproduces flip/flip/transpose exactly — but nothing about "flip" or "transpose"
was ever named in the code. Geometry became a special case of attention, learned
from scratch, first try.
</p>
</div>
</div>
<div class="lesson" id="l4-3">
<div class="lesson-head">
<span class="lesson-loc">4.3</span>
<h3>The composition pattern</h3>
</div>
<div class="lesson-body">
<p>
Naively fitting one memory that does both geometry <em>and</em> colour hits a
structural wall: geometry needs a <em>soft</em> gather to have a usable gradient,
colour needs <em>sharp</em> bins to stay clean, and one shared temperature can't
serve both — a free colour table will quietly absorb geometry error at the wrong
position, flattening the very signal the ES needs.
</p>
<div class="callout callout-neg">
<span class="callout-label">Negative result, recorded</span>
<p>A single combined geometry+colour memory was tried and abandoned — it only
reached the bar under hand-staging (stone soup, 3.5). The fix was a different
factorization, not more tuning.</p>
</div>
<p>
The recipe that replaced it, now proven three times over: find a representation
where the two factors <strong>commute</strong>, fit each factor on a signal the
other one cannot touch, then compose forward. Concretely — the colour table is
written <em>closed-form</em> from count signatures that are position-free (so
geometry can't corrupt them), and the geometry ES then runs on demos already
pre-mapped through that fixed colour table.