eyeling 1.16.2 → 1.16.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/HANDBOOK.md +4 -0
  2. package/README.md +0 -1
  3. package/examples/ershov-mixed-computation.n3 +106 -0
  4. package/examples/output/ershov-mixed-computation.n3 +15 -0
  5. package/eyeling.js +510 -263
  6. package/lib/cli.js +22 -12
  7. package/lib/engine.js +488 -251
  8. package/package.json +2 -3
  9. package/arctifacts/README.md +0 -59
  10. package/arctifacts/ackermann.html +0 -678
  11. package/arctifacts/auroracare.html +0 -1297
  12. package/arctifacts/bike-trip.html +0 -752
  13. package/arctifacts/binomial-theorem.html +0 -631
  14. package/arctifacts/bmi.html +0 -511
  15. package/arctifacts/building-performance.html +0 -750
  16. package/arctifacts/clinical-care.html +0 -726
  17. package/arctifacts/collatz.html +0 -403
  18. package/arctifacts/complex.html +0 -321
  19. package/arctifacts/control-system.html +0 -482
  20. package/arctifacts/delfour.html +0 -849
  21. package/arctifacts/earthquake-epicenter.html +0 -982
  22. package/arctifacts/eco-route.html +0 -662
  23. package/arctifacts/euclid-infinitude.html +0 -564
  24. package/arctifacts/euler-identity.html +0 -667
  25. package/arctifacts/exoplanet-transit.html +0 -1000
  26. package/arctifacts/faltings-theorem.html +0 -1046
  27. package/arctifacts/fibonacci.html +0 -299
  28. package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
  29. package/arctifacts/godel-numbering.html +0 -743
  30. package/arctifacts/gps-bike.html +0 -759
  31. package/arctifacts/gps-clinical-bench.html +0 -792
  32. package/arctifacts/graph-french.html +0 -449
  33. package/arctifacts/grass-molecular.html +0 -592
  34. package/arctifacts/group-theory.html +0 -740
  35. package/arctifacts/health-info.html +0 -833
  36. package/arctifacts/kaprekar-constant.html +0 -576
  37. package/arctifacts/lee.html +0 -805
  38. package/arctifacts/linked-lists.html +0 -502
  39. package/arctifacts/lldm.html +0 -612
  40. package/arctifacts/matrix-multiplication.html +0 -502
  41. package/arctifacts/matrix.html +0 -651
  42. package/arctifacts/newton-raphson.html +0 -944
  43. package/arctifacts/peano-factorial.html +0 -456
  44. package/arctifacts/pi.html +0 -363
  45. package/arctifacts/polynomial.html +0 -646
  46. package/arctifacts/prime.html +0 -366
  47. package/arctifacts/pythagorean-theorem.html +0 -468
  48. package/arctifacts/rest-path.html +0 -469
  49. package/arctifacts/roots-of-unity.html +0 -363
  50. package/arctifacts/turing.html +0 -409
  51. package/arctifacts/wind-turbines.html +0 -726
@@ -1,740 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>Group Theory</title>
7
- <style>
8
- :root {
9
- --bg: #ffffff;
10
- --ink: #111827;
11
- --muted: #6b7280;
12
- --panel: #f8fafc;
13
- --border: #e5e7eb;
14
- --accent: #0ea5e9;
15
- --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
16
- --ui:
17
- system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'Apple Color Emoji',
18
- 'Segoe UI Emoji';
19
- }
20
- html,
21
- body {
22
- height: 100%;
23
- }
24
- body {
25
- margin: 0;
26
- background: var(--bg);
27
- color: var(--ink);
28
- font: 15px/1.5 var(--ui);
29
- }
30
- .wrap {
31
- max-width: 980px;
32
- margin: 36px auto;
33
- padding: 0 16px;
34
- }
35
- header {
36
- display: flex;
37
- align-items: center;
38
- justify-content: space-between;
39
- margin-bottom: 16px;
40
- }
41
- h1 {
42
- font-size: 22px;
43
- margin: 0;
44
- letter-spacing: 0.2px;
45
- }
46
- .pill {
47
- display: inline-flex;
48
- align-items: center;
49
- gap: 8px;
50
- padding: 6px 10px;
51
- border: 1px solid var(--border);
52
- border-radius: 999px;
53
- color: var(--muted);
54
- background: #fff;
55
- }
56
- .row {
57
- display: flex;
58
- flex-direction: column;
59
- gap: 16px;
60
- }
61
- .card {
62
- flex: 1 1 auto;
63
- background: var(--panel);
64
- border: 1px solid var(--border);
65
- border-radius: 14px;
66
- overflow: hidden;
67
- }
68
- .head {
69
- display: flex;
70
- align-items: center;
71
- justify-content: space-between;
72
- padding: 10px 12px;
73
- border-bottom: 1px solid var(--border);
74
- }
75
- .head h2 {
76
- font-size: 13px;
77
- text-transform: uppercase;
78
- letter-spacing: 0.08em;
79
- color: var(--muted);
80
- margin: 0;
81
- }
82
- .body {
83
- padding: 12px;
84
- }
85
- pre {
86
- white-space: pre-wrap;
87
- background: #fff;
88
- border: 1px solid var(--border);
89
- border-radius: 10px;
90
- padding: 12px;
91
- overflow: auto;
92
- font-family: var(--mono);
93
- font-size: 13px;
94
- }
95
- .bar {
96
- display: flex;
97
- gap: 8px;
98
- margin-top: 10px;
99
- flex-wrap: wrap;
100
- }
101
- button {
102
- all: unset;
103
- background: #fff;
104
- border: 1px solid var(--border);
105
- padding: 8px 12px;
106
- border-radius: 10px;
107
- cursor: pointer;
108
- }
109
- button:hover {
110
- border-color: #cbd5e1;
111
- }
112
- .small {
113
- color: var(--muted);
114
- text-decoration: none;
115
- }
116
- .accent {
117
- color: var(--accent);
118
- }
119
-
120
- /* ARC v2 (Cards) */
121
- .arc-grid {
122
- display: flex;
123
- flex-direction: column;
124
- gap: 12px;
125
- }
126
- .arc-card {
127
- background: #fff;
128
- border: 1px solid var(--border);
129
- border-radius: 14px;
130
- overflow: hidden;
131
- }
132
- .arc-card .ac-head {
133
- display: flex;
134
- align-items: center;
135
- gap: 8px;
136
- padding: 10px 12px;
137
- border-bottom: 1px solid var(--border);
138
- font-size: 12px;
139
- letter-spacing: 0.08em;
140
- text-transform: uppercase;
141
- color: var(--muted);
142
- }
143
- .arc-card .ac-body {
144
- padding: 12px;
145
- }
146
- .arc-card pre {
147
- margin: 0;
148
- white-space: pre-wrap;
149
- background: #fff;
150
- border: 1px solid #eef2f7;
151
- border-radius: 10px;
152
- padding: 10px;
153
- font-family: var(--mono);
154
- font-size: 13px;
155
- }
156
- .arc-card.answer {
157
- border-left: 4px solid #10b981;
158
- }
159
- .arc-card.reason {
160
- border-left: 4px solid #3b82f6;
161
- }
162
- .arc-card.check {
163
- border-left: 4px solid #f59e0b;
164
- }
165
- .toolbar {
166
- display: flex;
167
- gap: 8px;
168
- align-items: center;
169
- }
170
- </style>
171
- </head>
172
- <body>
173
- <div class="wrap">
174
- <header>
175
- <h1>Group Theory</h1>
176
- <div class="pill">Self‑contained • No deps</div>
177
- </header>
178
-
179
- <div class="card" style="margin-bottom: 16px">
180
- <div class="body">
181
- <p>
182
- <strong>What this is?</strong> A self‑contained, browser‑only <em>ARC harness</em> that demonstrates finite
183
- group theory with three small groups: Z/12Z (addition mod 12), S₄ (permutations on 4 symbols), and GL(2, Z₅)
184
- (invertible 2×2 matrices mod 5). It prints results and a verification harness entirely on this page—no
185
- network, no libraries.
186
- </p>
187
- <p>
188
- <strong>How to use it:</strong> Press <em>Run</em> to generate the analysis and optionally export the ARC
189
- report. The output is organized as <em>Answer</em> (results), <em>Reason why</em> (explanations), and
190
- <em>Check</em> (axioms/homomorphisms and sanity tests).
191
- </p>
192
- <p class="small">
193
- This page is for reproducibility and documentation; it is not a substitute for a group theory text.
194
- </p>
195
- </div>
196
- </div>
197
-
198
- <div class="row">
199
- <div class="card">
200
- <div class="head">
201
- <h2>Run</h2>
202
- <div class="bar">
203
- <button onclick="run()">▶ Run</button>
204
- <a
205
- href="#"
206
- class="small"
207
- onclick="
208
- copyARC();
209
- return false;
210
- "
211
- >Copy ARC</a
212
- >
213
- </div>
214
- </div>
215
- <div class="body">
216
- <div class="small">
217
- Deterministic sampling with a fixed seed; computation happens locally in your browser.
218
- </div>
219
- </div>
220
- </div>
221
- <div class="card">
222
- <div class="head">
223
- <h2>ARC Output</h2>
224
- <div class="toolbar">
225
- <button onclick="toggleArcStyle()" id="styleBtn">Style: Cards</button>
226
- <button onclick="downloadARC()">⬇ Export .txt</button>
227
- </div>
228
- </div>
229
- <div class="body">
230
- <div id="arc-cards" class="arc-grid">
231
- <div class="arc-card answer">
232
- <div class="ac-head">Answer</div>
233
- <div class="ac-body"><pre id="arc_ans">(no run yet)</pre></div>
234
- </div>
235
- <div class="arc-card reason">
236
- <div class="ac-head">Reason why</div>
237
- <div class="ac-body"><pre id="arc_reason">(no run yet)</pre></div>
238
- </div>
239
- <div class="arc-card check">
240
- <div class="ac-head">Check (harness)</div>
241
- <div class="ac-body"><pre id="arc_check">(no run yet)</pre></div>
242
- </div>
243
- </div>
244
- <pre id="arc" style="display: none">(no run yet)</pre>
245
- </div>
246
- </div>
247
- </div>
248
- </div>
249
-
250
- <script>
251
- // ---------- Utilities ----------
252
- function downloadText(name, text) {
253
- const blob = new Blob([text], { type: 'text/plain' });
254
- const a = document.createElement('a');
255
- a.href = URL.createObjectURL(blob);
256
- a.download = name;
257
- document.body.appendChild(a);
258
- a.click();
259
- a.remove();
260
- }
261
- function copyARC() {
262
- navigator.clipboard.writeText(document.getElementById('arc').textContent);
263
- }
264
-
265
- // Deterministic PRNG (LCG) for repeatable sampling
266
- function makeRand(seed = 0xc0ffee) {
267
- let s = seed >>> 0;
268
- return function () {
269
- s = (1664525 * s + 1013904223) >>> 0;
270
- return (s >>> 0) / 4294967296;
271
- };
272
- }
273
- function choice(arr, rand) {
274
- return arr[Math.floor(rand() * arr.length)];
275
- }
276
-
277
- // ---------- Generic FiniteGroup shell ----------
278
- class FiniteGroup {
279
- elements() {
280
- throw new Error('Not implemented');
281
- }
282
- op(a, b) {
283
- throw new Error('Not implemented');
284
- }
285
- e() {
286
- throw new Error('Not implemented');
287
- }
288
- inv(a) {
289
- throw new Error('Not implemented');
290
- }
291
- name() {
292
- return this.constructor.name;
293
- }
294
- pow(a, n) {
295
- if (n < 0) throw new Error('Exponent must be non-negative.');
296
- let r = this.e(),
297
- b = a,
298
- k = n;
299
- while (k) {
300
- if (k & 1) r = this.op(r, b);
301
- b = this.op(b, b);
302
- k >>= 1;
303
- }
304
- return r;
305
- }
306
- }
307
-
308
- // ---------- Concrete groups ----------
309
- // Z/nZ under addition
310
- class Zmod extends FiniteGroup {
311
- constructor(n) {
312
- super();
313
- this.n = n;
314
- this._elems = null;
315
- }
316
- elements() {
317
- return (this._elems ??= Array.from({ length: this.n }, (_, i) => i));
318
- }
319
- op(a, b) {
320
- return (a + b) % this.n;
321
- }
322
- e() {
323
- return 0;
324
- }
325
- inv(a) {
326
- return ((-a % this.n) + this.n) % this.n;
327
- }
328
- name() {
329
- return `Z/${this.n}Z`;
330
- }
331
- }
332
-
333
- // S_n as permutations (arrays), op = composition (apply right then left)
334
- class SymmetricGroup extends FiniteGroup {
335
- constructor(n) {
336
- super();
337
- this.n = n;
338
- this._elems = null;
339
- }
340
- elements() {
341
- return (this._elems ??= permute(Array.from({ length: this.n }, (_, i) => i)));
342
- }
343
- op(p, q) {
344
- // i ↦ p[q[i]]
345
- const n = this.n,
346
- r = new Array(n);
347
- for (let i = 0; i < n; i++) r[i] = p[q[i]];
348
- return r;
349
- }
350
- e() {
351
- return Array.from({ length: this.n }, (_, i) => i);
352
- }
353
- inv(p) {
354
- const n = this.n,
355
- inv = new Array(n);
356
- for (let i = 0; i < n; i++) inv[p[i]] = i;
357
- return inv;
358
- }
359
- name() {
360
- return `S_${this.n}`;
361
- }
362
- }
363
- function permute(arr) {
364
- const res = [];
365
- function backtrack(a, i) {
366
- if (i === a.length) {
367
- res.push(a.slice());
368
- return;
369
- }
370
- for (let j = i; j < a.length; j++) {
371
- [a[i], a[j]] = [a[j], a[i]];
372
- backtrack(a, i + 1);
373
- [a[i], a[j]] = [a[j], a[i]];
374
- }
375
- }
376
- backtrack(arr.slice(), 0);
377
- return res;
378
- }
379
-
380
- // GL(2, Z_p): matrices [A,B,C,D] with det ≠ 0 mod p
381
- class GL2Zp extends FiniteGroup {
382
- constructor(p) {
383
- super();
384
- this.p = p;
385
- this._elems = null;
386
- }
387
- _mod(x) {
388
- const p = this.p;
389
- x %= p;
390
- return x < 0 ? x + p : x;
391
- }
392
- _det(M) {
393
- const [A, B, C, D] = M;
394
- return this._mod(A * D - B * C);
395
- }
396
- _inv_mod(a) {
397
- const p = this.p;
398
- a %= p;
399
- if (a < 0) a += p;
400
- if (a === 0) throw new Error('no inverse mod p');
401
- let t = 0,
402
- newt = 1,
403
- r = p,
404
- newr = a;
405
- while (newr !== 0) {
406
- const q = Math.floor(r / newr);
407
- [t, newt] = [newt, t - q * newt];
408
- [r, newr] = [newr, r - q * newr];
409
- }
410
- if (r !== 1) throw new Error('not invertible mod p');
411
- t %= p;
412
- if (t < 0) t += p;
413
- return t;
414
- }
415
- elements() {
416
- if (this._elems) return this._elems;
417
- const p = this.p,
418
- elems = [];
419
- for (let A = 0; A < p; A++)
420
- for (let B = 0; B < p; B++)
421
- for (let C = 0; C < p; C++)
422
- for (let D = 0; D < p; D++) {
423
- if ((((A * D - B * C) % p) + p) % p !== 0) elems.push([A, B, C, D]);
424
- }
425
- this._elems = elems;
426
- return elems;
427
- }
428
- op(M, N) {
429
- const p = this.p;
430
- const [A, B, C, D] = M,
431
- [E, F, G, H] = N;
432
- return [(A * E + B * G) % p, (A * F + B * H) % p, (C * E + D * G) % p, (C * F + D * H) % p].map(
433
- (x) => ((x % p) + p) % p,
434
- );
435
- }
436
- e() {
437
- return [1, 0, 0, 1];
438
- }
439
- inv(M) {
440
- const [A, B, C, D] = M;
441
- const det = this._det(M),
442
- inv_det = this._inv_mod(det);
443
- return [(D * inv_det) % this.p, (-B * inv_det) % this.p, (-C * inv_det) % this.p, (A * inv_det) % this.p].map(
444
- (x) => ((x % this.p) + this.p) % this.p,
445
- );
446
- }
447
- name() {
448
- return `GL(2, Z_${this.p})`;
449
- }
450
- }
451
-
452
- // ---------- Checks & helpers ----------
453
- function permutation_parity(p) {
454
- // 0 even, 1 odd
455
- let inv = 0,
456
- n = p.length;
457
- for (let i = 0; i < n; i++) for (let j = i + 1; j < n; j++) if (p[i] > p[j]) inv++;
458
- return inv & 1;
459
- }
460
- function check_homomorphism(G, H, phi, { exhaustive = false, samples = 5000, rand = Math.random } = {}) {
461
- const elemsG = G.elements();
462
- if (exhaustive || elemsG.length <= 200) {
463
- for (const a of elemsG)
464
- for (const b of elemsG) {
465
- const lhs = phi(G.op(a, b)),
466
- rhs = H.op(phi(a), phi(b));
467
- if (!eq(lhs, rhs)) return false;
468
- }
469
- return true;
470
- } else {
471
- for (let k = 0; k < samples; k++) {
472
- const a = choice(elemsG, rand),
473
- b = choice(elemsG, rand);
474
- const lhs = phi(G.op(a, b)),
475
- rhs = H.op(phi(a), phi(b));
476
- if (!eq(lhs, rhs)) return false;
477
- }
478
- return true;
479
- }
480
- }
481
- function element_order(G, a) {
482
- const e = G.e();
483
- let acc = Array.isArray(a) ? a.slice() : a; // clone arrays
484
- let k = 1,
485
- safety = 10000;
486
- while (!eq(acc, e)) {
487
- acc = G.op(acc, a);
488
- k++;
489
- if (k > safety) return -1;
490
- }
491
- return k;
492
- }
493
- function find_noncommuting_pair(G) {
494
- const elems = G.elements();
495
- for (const a of elems)
496
- for (const b of elems) {
497
- if (!eq(G.op(a, b), G.op(b, a))) return [a, b];
498
- }
499
- return null;
500
- }
501
- function all_orders_divide_group_order(G) {
502
- const n = G.elements().length;
503
- for (const g of G.elements()) {
504
- const k = element_order(G, g);
505
- if (n % k !== 0) return false;
506
- }
507
- return true;
508
- }
509
- function eq(a, b) {
510
- if (Array.isArray(a) && Array.isArray(b)) {
511
- if (a.length !== b.length) return false;
512
- for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
513
- return true;
514
- }
515
- return a === b;
516
- }
517
- function show(obj) {
518
- return JSON.stringify(obj);
519
- }
520
-
521
- // ---------- ARC run ----------
522
- function run() {
523
- const rnd = makeRand(0xc0ffee);
524
-
525
- // Groups
526
- const Z12 = new Zmod(12);
527
- const S4 = new SymmetricGroup(4);
528
- const GL25 = new GL2Zp(5);
529
-
530
- // Sample operations / elements
531
- const aZ = 7,
532
- bZ = 10,
533
- abZ = Z12.op(aZ, bZ),
534
- invZ = Z12.inv(aZ);
535
- const p = [1, 0, 2, 3],
536
- q = [2, 1, 0, 3];
537
- const pq = S4.op(p, q),
538
- invp = S4.inv(p);
539
- const M = [2, 1, 0, 1],
540
- N = [1, 1, 1, 2];
541
- const MN = GL25.op(M, N),
542
- invM = GL25.inv(M);
543
- const noncomm_pair_S4 = find_noncommuting_pair(S4);
544
- const noncomm_pair_GL = find_noncommuting_pair(GL25);
545
-
546
- // Homomorphisms
547
- const Z4 = new Zmod(4);
548
- const phi = (x) => x % 4;
549
- const phi_is_hom = check_homomorphism(Z12, Z4, phi, { exhaustive: true });
550
- const ker_phi = Z12.elements().filter((x) => phi(x) === Z4.e());
551
- const im_phi = Array.from(new Set(Z12.elements().map((x) => phi(x)))).sort((a, b) => a - b);
552
- const fit_ok = Z12.elements().length / ker_phi.length === im_phi.length;
553
-
554
- const C2 = new Zmod(2);
555
- const sgn = (perm) => permutation_parity(perm);
556
- const sgn_is_hom = check_homomorphism(S4, C2, sgn, { exhaustive: true });
557
- const ker_sgn = S4.elements().filter((s) => sgn(s) === 0);
558
- const index_A4 = S4.elements().length / ker_sgn.length;
559
-
560
- // Orders & Cauchy witnesses
561
- const orders_Z12 = Object.fromEntries(Z12.elements().map((x) => [x, element_order(Z12, x)]));
562
- const elem_order2_S4 = S4.elements().find((g) => element_order(S4, g) === 2) ?? null;
563
- const elem_order3_S4 = S4.elements().find((g) => element_order(S4, g) === 3) ?? null;
564
- const elem_order2_GL = GL25.elements().find((g) => element_order(GL25, g) === 2) ?? null;
565
- const elem_order3_GL = GL25.elements().find((g) => element_order(GL25, g) === 3) ?? null;
566
- const elem_order5_GL = GL25.elements().find((g) => element_order(GL25, g) === 5) ?? null;
567
-
568
- // Lagrange sanity
569
- const lagrange_Z12 = all_orders_divide_group_order(Z12);
570
- const lagrange_S4 = all_orders_divide_group_order(S4);
571
- const lagrange_GL25 = all_orders_divide_group_order(GL25);
572
-
573
- // ---- Build ARC sections separately ----
574
- const A = [];
575
- const R = [];
576
- const C = [];
577
-
578
- // Answer
579
- A.push(
580
- `Groups: ${Z12.name()} (|G|=${Z12.elements().length}), ${S4.name()} (|G|=${S4.elements().length}), ${GL25.name()} (|G|=${GL25.elements().length})`,
581
- );
582
- A.push('');
583
- A.push('Sample operations:');
584
- A.push(`Z/12Z: ${aZ} + ${bZ} ≡ ${abZ} (mod 12); inverse(${aZ}) = ${invZ}`);
585
- A.push(
586
- `S4: compose p=${JSON.stringify(p)} after q=${JSON.stringify(q)} → p∘q=${JSON.stringify(pq)}; inv(p)=${JSON.stringify(invp)}`,
587
- );
588
- A.push(
589
- `GL(2,5): M=${JSON.stringify(M)}, N=${JSON.stringify(N)}, M·N=${JSON.stringify(MN)}; M⁻¹=${JSON.stringify(invM)}`,
590
- );
591
- if (noncomm_pair_S4) {
592
- const [a, b] = noncomm_pair_S4;
593
- A.push(`Non-abelian witness for S4: a*b ≠ b*a for a=${JSON.stringify(a)}, b=${JSON.stringify(b)}`);
594
- }
595
- if (noncomm_pair_GL) {
596
- const [a, b] = noncomm_pair_GL;
597
- A.push(`Non-abelian witness for GL(2,5): a*b ≠ b*a for a=${JSON.stringify(a)}, b=${JSON.stringify(b)}`);
598
- }
599
-
600
- // Reason why
601
- R.push('We model groups directly: a finite set, an operation, identity, and inverses.');
602
- R.push('Each concrete group implements these and we verify the axioms by computation.');
603
- R.push('Homomorphisms preserve structure (φ(a*b)=φ(a)·φ(b)); we check this for:');
604
- R.push(' • φ: Z/12Z→Z/4Z (reduction mod 4), and • sgn: S4→C2 (parity).');
605
- R.push('The First Isomorphism Theorem claims Z12/ker(φ) ≅ im(φ); we validate the size relation.');
606
- R.push('Cauchy’s theorem predicts elements with prime orders dividing |G|; we find examples.');
607
- R.push('Lagrange’s theorem predicts order(g) | |G|; we confirm this holds for all g in each group.');
608
-
609
- // Check (harness)
610
- C.push('Axiom checks (associativity exhaustive for small groups; sampled for GL(2,5)):');
611
- const res_Z12 = check_group_axioms(Z12, { exhaustive_assoc: true });
612
- C.push(` ${Z12.name()}: ${JSON.stringify(res_Z12)}`);
613
- const res_S4 = check_group_axioms(S4, { exhaustive_assoc: true });
614
- C.push(` ${S4.name()}: ${JSON.stringify(res_S4)}`);
615
- const res_GL25 = check_group_axioms(GL25, { exhaustive_assoc: false, assoc_samples: 8000, rand: rnd });
616
- C.push(` ${GL25.name()}: ${JSON.stringify(res_GL25)} (associativity via 8000 random triples)`);
617
- C.push('');
618
- C.push('Abelian?');
619
- C.push(` ${Z12.name()}: ${is_abelian(Z12)}`);
620
- C.push(` ${S4.name()}: ${is_abelian(S4)}`);
621
- C.push(` ${GL25.name()}: ${is_abelian(GL25)}`);
622
- C.push('');
623
- const Z4b = new Zmod(4);
624
- const phi2 = (x) => x % 4;
625
- const ok_phi = check_homomorphism(Z12, Z4b, phi2, { exhaustive: true });
626
- const C2b = new Zmod(2);
627
- const sgn2 = (perm) => permutation_parity(perm);
628
- const ok_sgn = check_homomorphism(S4, C2b, sgn2, { exhaustive: true });
629
- C.push(`Homomorphism laws hold? φ: ${ok_phi}, sgn: ${ok_sgn}`);
630
- let ok_inv_samples = true;
631
- for (let t = 0; t < 10; t++) {
632
- const g = choice(GL25.elements(), rnd);
633
- if (!eq(GL25.op(g, GL25.inv(g)), GL25.e()) || !eq(GL25.op(GL25.inv(g), g), GL25.e())) {
634
- ok_inv_samples = false;
635
- break;
636
- }
637
- }
638
- C.push(`GL(2,5) random inverse sanity (10 samples): ${ok_inv_samples}`);
639
-
640
- // Populate the new card view
641
- document.getElementById('arc_ans').textContent = A.join('\n');
642
- document.getElementById('arc_reason').textContent = R.join('\n');
643
- document.getElementById('arc_check').textContent = C.join('\n');
644
-
645
- // Keep a combined plain-text for copy/export
646
- const combined = [
647
- 'Answer',
648
- '------',
649
- ...A,
650
- '',
651
- 'Reason why',
652
- '----------',
653
- ...R,
654
- '',
655
- 'Check (harness)',
656
- '---------------',
657
- ...C,
658
- ].join('\n');
659
- document.getElementById('arc').textContent = combined;
660
- }
661
-
662
- // Supporting checks used in the harness
663
- function check_group_axioms(G, { exhaustive_assoc = false, assoc_samples = 5000, rand = Math.random } = {}) {
664
- const elems = G.elements();
665
- const e = G.e();
666
- let ok_assoc = true;
667
- if (exhaustive_assoc) {
668
- outer: for (const a of elems) {
669
- for (const b of elems) {
670
- for (const c of elems) {
671
- if (!eq(G.op(G.op(a, b), c), G.op(a, G.op(b, c)))) {
672
- ok_assoc = false;
673
- break outer;
674
- }
675
- }
676
- }
677
- }
678
- } else {
679
- for (let i = 0; i < assoc_samples; i++) {
680
- const a = choice(elems, rand),
681
- b = choice(elems, rand),
682
- c = choice(elems, rand);
683
- if (!eq(G.op(G.op(a, b), c), G.op(a, G.op(b, c)))) {
684
- ok_assoc = false;
685
- break;
686
- }
687
- }
688
- }
689
- const ok_ident = elems.every((a) => eq(G.op(e, a), a) && eq(G.op(a, e), a));
690
- const ok_inv = elems.every((a) => eq(G.op(a, G.inv(a)), e) && eq(G.op(G.inv(a), a), e));
691
- let ok_closure = true;
692
- const limit = Math.min(1000, elems.length * elems.length);
693
- for (let i = 0; i < limit; i++) {
694
- const a = choice(elems, rand),
695
- b = choice(elems, rand);
696
- if (!contains(elems, G.op(a, b))) {
697
- ok_closure = false;
698
- break;
699
- }
700
- }
701
- return { associativity: ok_assoc, identity: ok_ident, inverses: ok_inv, closure: ok_closure };
702
- }
703
- function is_abelian(G) {
704
- const elems = G.elements();
705
- for (const a of elems)
706
- for (const b of elems) {
707
- if (!eq(G.op(a, b), G.op(b, a))) return false;
708
- }
709
- return true;
710
- }
711
- function contains(arr, x) {
712
- if (Array.isArray(x)) return arr.some((y) => eq(y, x));
713
- return arr.includes(x);
714
- }
715
-
716
- function toggleArcStyle() {
717
- const pre = document.getElementById('arc');
718
- const cards = document.getElementById('arc-cards');
719
- const btn = document.getElementById('styleBtn');
720
- const showingCards = cards.style.display !== 'none';
721
- if (showingCards) {
722
- cards.style.display = 'none';
723
- pre.style.display = 'block';
724
- btn.textContent = 'Style: Plain';
725
- } else {
726
- cards.style.display = 'block';
727
- pre.style.display = 'none';
728
- btn.textContent = 'Style: Cards';
729
- }
730
- }
731
- function downloadARC() {
732
- const text = document.getElementById('arc').textContent;
733
- downloadText('group_theory_arc.txt', text);
734
- }
735
-
736
- // bootstrap
737
- run();
738
- </script>
739
- </body>
740
- </html>