phanerozoic commited on
Commit
8a111f6
·
verified ·
1 Parent(s): 7f0f2cc

Delete test_timing.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. test_timing.py +0 -510
test_timing.py DELETED
@@ -1,510 +0,0 @@
1
- """
2
- TEST #5: Timing Analysis
3
- =========================
4
- Build circuit DAG, compute critical path depth.
5
- Prove worst-case carry propagation takes exactly the expected number of layers.
6
-
7
- A skeptic would demand: "Show me the circuit depth. Prove the critical path."
8
- """
9
-
10
- import torch
11
- from safetensors.torch import load_file
12
- from collections import defaultdict
13
-
14
- # Load circuits
15
- model = load_file('neural_computer.safetensors')
16
-
17
- # =============================================================================
18
- # CIRCUIT DEPTH DEFINITIONS
19
- # =============================================================================
20
-
21
- # Depth of primitive gates (in threshold layers)
22
- GATE_DEPTHS = {
23
- 'AND': 1, # Single threshold neuron
24
- 'OR': 1, # Single threshold neuron
25
- 'NOT': 1, # Single threshold neuron
26
- 'NAND': 1, # Single threshold neuron
27
- 'NOR': 1, # Single threshold neuron
28
- 'XOR': 2, # Two layers: (OR, NAND) -> AND
29
- 'XNOR': 2, # Two layers: (NOR, AND) -> OR
30
- }
31
-
32
- def half_adder_depth():
33
- """
34
- Half adder: sum = XOR(a,b), carry = AND(a,b)
35
- Critical path: max(XOR, AND) = max(2, 1) = 2
36
- """
37
- sum_depth = GATE_DEPTHS['XOR'] # 2
38
- carry_depth = GATE_DEPTHS['AND'] # 1
39
- return {
40
- 'sum': sum_depth,
41
- 'carry': carry_depth,
42
- 'critical': max(sum_depth, carry_depth)
43
- }
44
-
45
- def full_adder_depth():
46
- """
47
- Full adder structure:
48
- HA1: (a, b) -> (s1 = XOR, c1 = AND)
49
- HA2: (s1, cin) -> (sum = XOR, c2 = AND) [depends on s1]
50
- cout = OR(c1, c2) [depends on c1 and c2]
51
-
52
- Critical path for sum:
53
- XOR(a,b) [2] -> XOR(s1, cin) [2] = 4 layers
54
-
55
- Critical path for carry:
56
- Option 1: AND(a,b) [1] -> OR [1] = 2 layers
57
- Option 2: XOR(a,b) [2] -> AND(s1,cin) [1] -> OR [1] = 4 layers
58
- Critical: max = 4 layers
59
- """
60
- # Sum path
61
- ha1_sum = GATE_DEPTHS['XOR'] # 2
62
- ha2_sum = ha1_sum + GATE_DEPTHS['XOR'] # 2 + 2 = 4
63
-
64
- # Carry path 1: through ha1_carry
65
- ha1_carry = GATE_DEPTHS['AND'] # 1
66
-
67
- # Carry path 2: through ha2
68
- ha2_carry = ha1_sum + GATE_DEPTHS['AND'] # 2 + 1 = 3
69
-
70
- # Final carry: OR of both carries
71
- cout = max(ha1_carry, ha2_carry) + GATE_DEPTHS['OR'] # max(1, 3) + 1 = 4
72
-
73
- return {
74
- 'ha1_sum': ha1_sum,
75
- 'ha1_carry': ha1_carry,
76
- 'ha2_sum': ha2_sum,
77
- 'ha2_carry': ha2_carry,
78
- 'sum': ha2_sum,
79
- 'carry': cout,
80
- 'critical': max(ha2_sum, cout)
81
- }
82
-
83
- def ripple_carry_depth(n_bits):
84
- """
85
- Ripple carry adder: chain of n full adders.
86
-
87
- FA0: sum[0], c0 (depth 4 each from inputs)
88
- FA1: sum[1], c1 (depends on c0, so +4 for carry path)
89
- ...
90
- FA(n-1): sum[n-1], c(n-1)
91
-
92
- Critical path is the carry chain:
93
- c0 ready at depth 4
94
- c1 = FA1.cout, depends on c0, adds 4 more (but only carry path matters)
95
-
96
- Actually, let's trace more carefully:
97
- FA_i.sum depends on FA_(i-1).cout
98
- FA_i.cout depends on FA_(i-1).cout
99
-
100
- Carry chain per FA after first:
101
- - cin arrives
102
- - XOR(a_i, b_i) was computed in parallel: 2 layers (can overlap)
103
- - HA2: XOR(s1, cin): 2 more layers from cin
104
- - OR(c1, c2): 1 more layer
105
-
106
- So from cin to cout of one FA:
107
- - If s1 is precomputed: 2 (HA2.XOR) + 1 (HA2.AND parallel) + 1 (OR) = 3?
108
-
109
- Let me be more precise. Within FA_i:
110
- - a_i, b_i available at time 0
111
- - s1 = XOR(a_i, b_i) ready at time 2
112
- - c1 = AND(a_i, b_i) ready at time 1
113
- - When cin arrives at time T:
114
- - s2 = XOR(s1, cin) ready at T + 2 (but s1 was ready at 2, so if T >= 2, it's T + 2)
115
- - c2 = AND(s1, cin) ready at max(2, T) + 1
116
- - cout = OR(c1, c2) ready at max(1, max(2,T)+1) + 1
117
-
118
- For FA0, cin = 0 (constant), so effectively T = 0:
119
- - sum[0] ready at 4
120
- - cout[0] ready at 4
121
-
122
- For FA1, cin = cout[0] arrives at T = 4:
123
- - s1 was ready at 2 (precomputed)
124
- - s2 = XOR(s1, cin) ready at 4 + 2 = 6
125
- - c2 = AND(s1, cin) ready at max(2, 4) + 1 = 5
126
- - cout[1] = OR(c1, c2) ready at max(1, 5) + 1 = 6
127
-
128
- Pattern: cout[i] ready at 4 + 2*i for i >= 0
129
-
130
- For 8-bit: cout[7] ready at 4 + 2*7 = 18 layers
131
- But sum[7] = 4 + 2*7 = 18 layers too
132
-
133
- Actually wait, let me re-examine. The carry propagation:
134
- cout[i] = OR(AND(a_i, b_i), AND(XOR(a_i, b_i), cin[i]))
135
-
136
- If we denote:
137
- P_i = XOR(a_i, b_i) -- propagate (ready at depth 2)
138
- G_i = AND(a_i, b_i) -- generate (ready at depth 1)
139
-
140
- Then:
141
- cout[i] = G_i OR (P_i AND cin[i])
142
- = G_i OR (P_i AND cout[i-1])
143
-
144
- Timing for cout[i] given cout[i-1] at time T:
145
- - G_i ready at 1
146
- - P_i ready at 2
147
- - P_i AND cout[i-1] ready at max(2, T) + 1
148
- - cout[i] ready at max(1, max(2, T) + 1) + 1 = max(2, T) + 2
149
-
150
- For i=0: cout[0] = G_0 OR (P_0 AND 0) = G_0, ready at 1? No wait, cin=0 constant.
151
- Actually if cin=0, then P_0 AND 0 = 0, so cout[0] = G_0 = AND(a_0, b_0), ready at depth 1.
152
- But we still compute the full FA, so cout[0] ready at depth... let's see:
153
- - G_0 ready at 1
154
- - P_0 ready at 2
155
- - HA2.carry = AND(P_0, 0) = 0, ready at max(2, 0) + 1 = 3 (but it's 0)
156
- - cout[0] = OR(G_0, 0) = G_0, ready at max(1, 3) + 1 = 4
157
-
158
- For i=1: cin[1] = cout[0] ready at 4
159
- - G_1 ready at 1
160
- - P_1 ready at 2
161
- - P_1 AND cin[1] ready at max(2, 4) + 1 = 5
162
- - cout[1] ready at max(1, 5) + 1 = 6
163
-
164
- For i=2: cin[2] = cout[1] ready at 6
165
- - cout[2] ready at max(2, 6) + 2 = 8
166
-
167
- Pattern: cout[i] = 4 + 2*i for i >= 0
168
- cout[0] = 4
169
- cout[1] = 6
170
- cout[7] = 4 + 14 = 18
171
-
172
- And sum[i] = XOR(P_i, cin[i]):
173
- sum[0] at max(2, 0) + 2 = 4
174
- sum[i] at max(2, cout[i-1]) + 2 = cout[i-1] + 2 = 4 + 2*(i-1) + 2 = 4 + 2*i
175
-
176
- So sum[7] ready at 4 + 14 = 18 layers.
177
-
178
- Critical path for 8-bit ripple carry: 18 threshold layers.
179
- """
180
- fa_depth = full_adder_depth()
181
-
182
- # First FA: inputs available at t=0, cin=0
183
- depths = {
184
- 'fa0_sum': 4,
185
- 'fa0_cout': 4,
186
- }
187
-
188
- # Subsequent FAs: depend on previous carry
189
- for i in range(1, n_bits):
190
- cin_ready = depths[f'fa{i-1}_cout']
191
- # P_i ready at 2, G_i ready at 1 (precomputed)
192
- # sum[i] = XOR(P_i, cin) ready at max(2, cin_ready) + 2
193
- # cout[i] ready at max(2, cin_ready) + 2
194
- depths[f'fa{i}_sum'] = max(2, cin_ready) + 2
195
- depths[f'fa{i}_cout'] = max(2, cin_ready) + 2
196
-
197
- critical_path = max(depths.values())
198
-
199
- return depths, critical_path
200
-
201
- def comparator_depth():
202
- """
203
- 8-bit comparator uses weighted sum of bit differences.
204
- Single threshold neuron comparing weighted sum to 0.
205
- Depth: 1 (just one threshold comparison)
206
- """
207
- return 1
208
-
209
- # =============================================================================
210
- # TIMING TESTS
211
- # =============================================================================
212
-
213
- def test_primitive_gates():
214
- """Verify primitive gate depths."""
215
- print("\n[TEST 1] Primitive Gate Depths")
216
- print("-" * 60)
217
-
218
- print(" Gate Layers Structure")
219
- print(" " + "-" * 40)
220
-
221
- primitives = [
222
- ('AND', 1, 'w*x + b >= 0'),
223
- ('OR', 1, 'w*x + b >= 0'),
224
- ('NOT', 1, 'w*x + b >= 0'),
225
- ('NAND', 1, 'w*x + b >= 0'),
226
- ('NOR', 1, 'w*x + b >= 0'),
227
- ('XOR', 2, 'Layer1(OR,NAND) -> Layer2(AND)'),
228
- ('XNOR', 2, 'Layer1(NOR,AND) -> Layer2(OR)'),
229
- ]
230
-
231
- for name, depth, structure in primitives:
232
- print(f" {name:6s} {depth} {structure}")
233
-
234
- print()
235
- print(" All single-layer gates: depth 1")
236
- print(" XOR/XNOR (non-linearly-separable): depth 2")
237
-
238
- return True
239
-
240
- def test_half_adder_depth():
241
- """Analyze half adder depth."""
242
- print("\n[TEST 2] Half Adder Depth Analysis")
243
- print("-" * 60)
244
-
245
- depths = half_adder_depth()
246
-
247
- print(" Component Depth Notes")
248
- print(" " + "-" * 45)
249
- print(f" sum (XOR) {depths['sum']} a XOR b")
250
- print(f" carry (AND) {depths['carry']} a AND b")
251
- print(f" Critical path {depths['critical']} max(sum, carry)")
252
-
253
- print()
254
- print(" Half adder critical path: 2 layers")
255
-
256
- return depths['critical'] == 2
257
-
258
- def test_full_adder_depth():
259
- """Analyze full adder depth."""
260
- print("\n[TEST 3] Full Adder Depth Analysis")
261
- print("-" * 60)
262
-
263
- depths = full_adder_depth()
264
-
265
- print(" Component Depth Path")
266
- print(" " + "-" * 50)
267
- print(f" HA1.sum (XOR) {depths['ha1_sum']} XOR(a, b)")
268
- print(f" HA1.carry (AND) {depths['ha1_carry']} AND(a, b)")
269
- print(f" HA2.sum (XOR) {depths['ha2_sum']} XOR(HA1.sum, cin)")
270
- print(f" HA2.carry (AND) {depths['ha2_carry']} AND(HA1.sum, cin)")
271
- print(f" cout (OR) {depths['carry']} OR(HA1.carry, HA2.carry)")
272
- print(f" Critical path {depths['critical']} max(sum, cout)")
273
-
274
- print()
275
- print(" Full adder critical path: 4 layers")
276
- print(" (XOR -> XOR for sum, or XOR -> AND -> OR for carry)")
277
-
278
- return depths['critical'] == 4
279
-
280
- def test_ripple_carry_depth():
281
- """Analyze n-bit ripple carry adder depths."""
282
- print("\n[TEST 4] Ripple Carry Adder Depth Analysis")
283
- print("-" * 60)
284
-
285
- for n in [2, 4, 8]:
286
- depths, critical = ripple_carry_depth(n)
287
- print(f"\n {n}-bit Ripple Carry Adder:")
288
- print(f" Critical path: {critical} layers")
289
-
290
- # Show carry chain timing
291
- carry_times = [depths[f'fa{i}_cout'] for i in range(n)]
292
- print(f" Carry chain: {carry_times}")
293
-
294
- # Show sum timing
295
- sum_times = [depths[f'fa{i}_sum'] for i in range(n)]
296
- print(f" Sum outputs: {sum_times}")
297
-
298
- print()
299
- print(" Pattern: depth = 4 + 2*(n-1) = 2n + 2")
300
- print(" 2-bit: 6 layers")
301
- print(" 4-bit: 10 layers")
302
- print(" 8-bit: 18 layers")
303
-
304
- # Verify formula
305
- for n, expected in [(2, 6), (4, 10), (8, 18)]:
306
- _, actual = ripple_carry_depth(n)
307
- if actual != expected:
308
- print(f" ERROR: {n}-bit expected {expected}, got {actual}")
309
- return False
310
-
311
- return True
312
-
313
- def test_worst_case_paths():
314
- """Identify worst-case input patterns."""
315
- print("\n[TEST 5] Worst-Case Carry Propagation Patterns")
316
- print("-" * 60)
317
-
318
- # Worst case: carry must propagate through all bits
319
- worst_cases = [
320
- (0b11111111, 0b00000001, "255 + 1: carry propagates 8 bits"),
321
- (0b01111111, 0b00000001, "127 + 1: carry propagates 7 bits"),
322
- (0b01111111, 0b10000000, "127 + 128: no carry propagation (bits don't overlap)"),
323
- (0b10101010, 0b01010101, "170 + 85: no carry (complementary patterns)"),
324
- (0b11111111, 0b11111111, "255 + 255: generate at each bit, propagate from bit 0"),
325
- ]
326
-
327
- print(" Input Pattern Result Carry Depth Notes")
328
- print(" " + "-" * 65)
329
-
330
- for a, b, desc in worst_cases:
331
- result = (a + b) % 256
332
- carry_out = (a + b) >> 8
333
-
334
- # Count how many bits need carry propagation
335
- # Carry propagates through bit i if P_i = a_i XOR b_i = 1
336
- propagate_bits = bin(a ^ b).count('1')
337
-
338
- # Longest carry chain: consecutive propagate bits from LSB
339
- chain_length = 0
340
- for i in range(8):
341
- if (a >> i) & 1 != (b >> i) & 1: # P_i = 1
342
- chain_length += 1
343
- elif (a >> i) & 1 == 1 and (b >> i) & 1 == 1: # G_i = 1
344
- chain_length += 1 # Generates carry, continues chain
345
- break # Chain ends (or starts new)
346
- else:
347
- break # Chain ends
348
-
349
- print(f" {a:3d} + {b:3d} = {result:3d} c={carry_out} {chain_length} bits {desc[:40]}")
350
-
351
- print()
352
- print(" 255 + 1 forces carry through all 8 full adders: worst case")
353
- print(" 127 + 128 has no overlapping bits: best case (no propagation)")
354
-
355
- return True
356
-
357
- def test_comparator_depth():
358
- """Analyze comparator depth."""
359
- print("\n[TEST 6] Comparator Depth Analysis")
360
- print("-" * 60)
361
-
362
- print(" 8-bit comparators use weighted positional comparison:")
363
- print(" GT: sum((a_i - b_i) * 2^(7-i)) > 0")
364
- print(" LT: sum((b_i - a_i) * 2^(7-i)) > 0")
365
- print()
366
- print(" Structure: Single threshold neuron")
367
- print(" Depth: 1 layer (just weighted sum comparison)")
368
- print()
369
- print(" Note: This is O(1) depth regardless of bit width!")
370
- print(" (Compared to ripple-carry which is O(n))")
371
-
372
- return True
373
-
374
- def test_circuit_depth_summary():
375
- """Summary of all circuit depths."""
376
- print("\n[TEST 7] Circuit Depth Summary")
377
- print("-" * 60)
378
-
379
- circuits = [
380
- ("AND/OR/NOT/NAND/NOR", 1),
381
- ("XOR/XNOR", 2),
382
- ("Half Adder", 2),
383
- ("Full Adder", 4),
384
- ("2-bit Ripple Carry", 6),
385
- ("4-bit Ripple Carry", 10),
386
- ("8-bit Ripple Carry", 18),
387
- ("8-bit Comparator", 1),
388
- ]
389
-
390
- print(" Circuit Depth (layers)")
391
- print(" " + "-" * 40)
392
- for name, depth in circuits:
393
- bar = "#" * depth
394
- print(f" {name:24s} {depth:3d} {bar}")
395
-
396
- print()
397
- print(" Observations:")
398
- print(" - Simple gates: O(1)")
399
- print(" - Ripple carry: O(n) where n = bit width")
400
- print(" - Comparator: O(1) - threshold logic advantage!")
401
-
402
- return True
403
-
404
- def test_verify_actual_structure():
405
- """Verify the actual tensor structure matches our depth analysis."""
406
- print("\n[TEST 8] Verify Tensor Structure Matches Analysis")
407
- print("-" * 60)
408
-
409
- errors = []
410
-
411
- # XOR should have layer1 and layer2
412
- xor_tensors = [k for k in model.keys() if k.startswith('boolean.xor')]
413
- has_layer1 = any('layer1' in k for k in xor_tensors)
414
- has_layer2 = any('layer2' in k for k in xor_tensors)
415
-
416
- if has_layer1 and has_layer2:
417
- print(" XOR: Has layer1 and layer2 tensors [OK]")
418
- else:
419
- print(" XOR: Missing layer structure [FAIL]")
420
- errors.append("XOR structure")
421
-
422
- # Full adder should have ha1, ha2, carry_or
423
- fa_tensors = [k for k in model.keys() if 'fulladder' in k]
424
- has_ha1 = any('ha1' in k for k in fa_tensors)
425
- has_ha2 = any('ha2' in k for k in fa_tensors)
426
- has_carry_or = any('carry_or' in k for k in fa_tensors)
427
-
428
- if has_ha1 and has_ha2 and has_carry_or:
429
- print(" Full Adder: Has ha1, ha2, carry_or [OK]")
430
- else:
431
- print(" Full Adder: Missing components [FAIL]")
432
- errors.append("FA structure")
433
-
434
- # Ripple carry should have fa0 through fa7
435
- rc8_tensors = [k for k in model.keys() if 'ripplecarry8bit' in k]
436
- fa_indices = set()
437
- for k in rc8_tensors:
438
- for i in range(8):
439
- if f'fa{i}' in k:
440
- fa_indices.add(i)
441
-
442
- if fa_indices == set(range(8)):
443
- print(f" 8-bit Ripple Carry: Has fa0-fa7 [OK]")
444
- else:
445
- print(f" 8-bit Ripple Carry: Missing FAs, found {fa_indices} [FAIL]")
446
- errors.append("RC8 structure")
447
-
448
- # Comparator should be single layer (no layer1/layer2)
449
- gt_tensors = [k for k in model.keys() if 'greaterthan8bit' in k]
450
- gt_has_layers = any('layer' in k for k in gt_tensors)
451
-
452
- if not gt_has_layers:
453
- print(" 8-bit Comparator: Single layer (no layer1/layer2) [OK]")
454
- else:
455
- print(" 8-bit Comparator: Has unexpected layer structure [FAIL]")
456
- errors.append("Comparator structure")
457
-
458
- print()
459
- if errors:
460
- print(f" Structure verification: {len(errors)} issues")
461
- return False
462
- else:
463
- print(" Structure verification: All circuits match expected topology")
464
- return True
465
-
466
- # =============================================================================
467
- # MAIN
468
- # =============================================================================
469
-
470
- if __name__ == "__main__":
471
- print("=" * 70)
472
- print(" TEST #5: TIMING ANALYSIS")
473
- print(" Circuit depth and critical path analysis")
474
- print("=" * 70)
475
-
476
- results = []
477
-
478
- results.append(("Primitive gates", test_primitive_gates()))
479
- results.append(("Half adder depth", test_half_adder_depth()))
480
- results.append(("Full adder depth", test_full_adder_depth()))
481
- results.append(("Ripple carry depth", test_ripple_carry_depth()))
482
- results.append(("Worst-case patterns", test_worst_case_paths()))
483
- results.append(("Comparator depth", test_comparator_depth()))
484
- results.append(("Depth summary", test_circuit_depth_summary()))
485
- results.append(("Structure verification", test_verify_actual_structure()))
486
-
487
- print("\n" + "=" * 70)
488
- print(" SUMMARY")
489
- print("=" * 70)
490
-
491
- passed = sum(1 for _, r in results if r)
492
- total = len(results)
493
-
494
- for name, r in results:
495
- status = "PASS" if r else "FAIL"
496
- print(f" {name:25s} [{status}]")
497
-
498
- print(f"\n Total: {passed}/{total} tests passed")
499
-
500
- print("\n Key Results:")
501
- print(" - 8-bit ripple carry: 18 threshold layers")
502
- print(" - 8-bit comparator: 1 threshold layer")
503
- print(" - Critical path formula: depth = 2n + 2 for n-bit adder")
504
-
505
- if passed == total:
506
- print("\n STATUS: TIMING ANALYSIS COMPLETE")
507
- else:
508
- print("\n STATUS: SOME TIMING TESTS FAILED")
509
-
510
- print("=" * 70)