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.
- package/HANDBOOK.md +4 -0
- package/README.md +0 -1
- package/examples/ershov-mixed-computation.n3 +106 -0
- package/examples/output/ershov-mixed-computation.n3 +15 -0
- package/eyeling.js +510 -263
- package/lib/cli.js +22 -12
- package/lib/engine.js +488 -251
- package/package.json +2 -3
- package/arctifacts/README.md +0 -59
- package/arctifacts/ackermann.html +0 -678
- package/arctifacts/auroracare.html +0 -1297
- package/arctifacts/bike-trip.html +0 -752
- package/arctifacts/binomial-theorem.html +0 -631
- package/arctifacts/bmi.html +0 -511
- package/arctifacts/building-performance.html +0 -750
- package/arctifacts/clinical-care.html +0 -726
- package/arctifacts/collatz.html +0 -403
- package/arctifacts/complex.html +0 -321
- package/arctifacts/control-system.html +0 -482
- package/arctifacts/delfour.html +0 -849
- package/arctifacts/earthquake-epicenter.html +0 -982
- package/arctifacts/eco-route.html +0 -662
- package/arctifacts/euclid-infinitude.html +0 -564
- package/arctifacts/euler-identity.html +0 -667
- package/arctifacts/exoplanet-transit.html +0 -1000
- package/arctifacts/faltings-theorem.html +0 -1046
- package/arctifacts/fibonacci.html +0 -299
- package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
- package/arctifacts/godel-numbering.html +0 -743
- package/arctifacts/gps-bike.html +0 -759
- package/arctifacts/gps-clinical-bench.html +0 -792
- package/arctifacts/graph-french.html +0 -449
- package/arctifacts/grass-molecular.html +0 -592
- package/arctifacts/group-theory.html +0 -740
- package/arctifacts/health-info.html +0 -833
- package/arctifacts/kaprekar-constant.html +0 -576
- package/arctifacts/lee.html +0 -805
- package/arctifacts/linked-lists.html +0 -502
- package/arctifacts/lldm.html +0 -612
- package/arctifacts/matrix-multiplication.html +0 -502
- package/arctifacts/matrix.html +0 -651
- package/arctifacts/newton-raphson.html +0 -944
- package/arctifacts/peano-factorial.html +0 -456
- package/arctifacts/pi.html +0 -363
- package/arctifacts/polynomial.html +0 -646
- package/arctifacts/prime.html +0 -366
- package/arctifacts/pythagorean-theorem.html +0 -468
- package/arctifacts/rest-path.html +0 -469
- package/arctifacts/roots-of-unity.html +0 -363
- package/arctifacts/turing.html +0 -409
- 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>
|