eyeling 1.16.3 → 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 (45) hide show
  1. package/README.md +0 -1
  2. package/package.json +2 -3
  3. package/arctifacts/README.md +0 -59
  4. package/arctifacts/ackermann.html +0 -678
  5. package/arctifacts/auroracare.html +0 -1297
  6. package/arctifacts/bike-trip.html +0 -752
  7. package/arctifacts/binomial-theorem.html +0 -631
  8. package/arctifacts/bmi.html +0 -511
  9. package/arctifacts/building-performance.html +0 -750
  10. package/arctifacts/clinical-care.html +0 -726
  11. package/arctifacts/collatz.html +0 -403
  12. package/arctifacts/complex.html +0 -321
  13. package/arctifacts/control-system.html +0 -482
  14. package/arctifacts/delfour.html +0 -849
  15. package/arctifacts/earthquake-epicenter.html +0 -982
  16. package/arctifacts/eco-route.html +0 -662
  17. package/arctifacts/euclid-infinitude.html +0 -564
  18. package/arctifacts/euler-identity.html +0 -667
  19. package/arctifacts/exoplanet-transit.html +0 -1000
  20. package/arctifacts/faltings-theorem.html +0 -1046
  21. package/arctifacts/fibonacci.html +0 -299
  22. package/arctifacts/fundamental-theorem-arithmetic.html +0 -398
  23. package/arctifacts/godel-numbering.html +0 -743
  24. package/arctifacts/gps-bike.html +0 -759
  25. package/arctifacts/gps-clinical-bench.html +0 -792
  26. package/arctifacts/graph-french.html +0 -449
  27. package/arctifacts/grass-molecular.html +0 -592
  28. package/arctifacts/group-theory.html +0 -740
  29. package/arctifacts/health-info.html +0 -833
  30. package/arctifacts/kaprekar-constant.html +0 -576
  31. package/arctifacts/lee.html +0 -805
  32. package/arctifacts/linked-lists.html +0 -502
  33. package/arctifacts/lldm.html +0 -612
  34. package/arctifacts/matrix-multiplication.html +0 -502
  35. package/arctifacts/matrix.html +0 -651
  36. package/arctifacts/newton-raphson.html +0 -944
  37. package/arctifacts/peano-factorial.html +0 -456
  38. package/arctifacts/pi.html +0 -363
  39. package/arctifacts/polynomial.html +0 -646
  40. package/arctifacts/prime.html +0 -366
  41. package/arctifacts/pythagorean-theorem.html +0 -468
  42. package/arctifacts/rest-path.html +0 -469
  43. package/arctifacts/roots-of-unity.html +0 -363
  44. package/arctifacts/turing.html +0 -409
  45. package/arctifacts/wind-turbines.html +0 -726
@@ -1,651 +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>Matrix basics</title>
7
- <style>
8
- :root {
9
- --bg: #ffffff;
10
- --ink: #111827;
11
- --muted: #6b7280;
12
- --panel: #f8fafc;
13
- --border: #e5e7eb;
14
- --accent: #0ea5e9;
15
- --good: #16a34a;
16
- --amber: #f59e0b;
17
- --blue: #3b82f6;
18
- --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
19
- --ui:
20
- system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'Apple Color Emoji',
21
- 'Segoe UI Emoji';
22
- }
23
- body {
24
- margin: 0;
25
- background: var(--bg);
26
- color: var(--ink);
27
- font: 15px/1.6 var(--ui);
28
- }
29
- .wrap {
30
- max-width: 980px;
31
- margin: 36px auto;
32
- padding: 0 16px;
33
- }
34
- header {
35
- display: flex;
36
- align-items: center;
37
- justify-content: space-between;
38
- margin-bottom: 16px;
39
- }
40
- h1 {
41
- font-size: 22px;
42
- margin: 0;
43
- letter-spacing: 0.2px;
44
- }
45
- .pill {
46
- display: inline-flex;
47
- align-items: center;
48
- gap: 8px;
49
- padding: 6px 10px;
50
- border: 1px solid var(--border);
51
- border-radius: 999px;
52
- color: var(--muted);
53
- background: #fff;
54
- }
55
- .row {
56
- display: flex;
57
- flex-direction: column;
58
- gap: 16px;
59
- }
60
- .card {
61
- background: var(--panel);
62
- border: 1px solid var(--border);
63
- border-radius: 14px;
64
- overflow: hidden;
65
- }
66
- .head {
67
- display: flex;
68
- align-items: center;
69
- justify-content: space-between;
70
- padding: 10px 12px;
71
- border-bottom: 1px solid var(--border);
72
- }
73
- .head h2 {
74
- font-size: 13px;
75
- text-transform: uppercase;
76
- letter-spacing: 0.08em;
77
- color: var(--muted);
78
- margin: 0;
79
- }
80
- .body {
81
- padding: 12px;
82
- }
83
- pre {
84
- white-space: pre-wrap;
85
- background: #fff;
86
- border: 1px solid var(--border);
87
- border-radius: 10px;
88
- padding: 12px;
89
- overflow: auto;
90
- font-family: var(--mono);
91
- font-size: 13.25px;
92
- }
93
- code {
94
- background: #fff;
95
- border: 1px solid var(--border);
96
- border-radius: 6px;
97
- padding: 0 6px;
98
- }
99
- .arc-grid {
100
- display: flex;
101
- flex-direction: column;
102
- gap: 12px;
103
- }
104
- .arc-card {
105
- background: #fff;
106
- border: 1px solid var(--border);
107
- border-radius: 14px;
108
- overflow: hidden;
109
- }
110
- .arc-card .ac-head {
111
- display: flex;
112
- align-items: center;
113
- gap: 8px;
114
- padding: 10px 12px;
115
- border-bottom: 1px solid var(--border);
116
- font-size: 12px;
117
- letter-spacing: 0.08em;
118
- text-transform: uppercase;
119
- color: var(--muted);
120
- }
121
- .arc-card .ac-body {
122
- padding: 12px;
123
- }
124
- .arc-card.answer {
125
- border-left: 4px solid var(--good);
126
- }
127
- .arc-card.reason {
128
- border-left: 4px solid var(--blue);
129
- }
130
- .arc-card.check {
131
- border-left: 4px solid var(--amber);
132
- }
133
- .btn {
134
- all: unset;
135
- background: #fff;
136
- border: 1px solid var(--border);
137
- padding: 8px 12px;
138
- border-radius: 10px;
139
- cursor: pointer;
140
- }
141
- .btn:hover {
142
- border-color: #cbd5e1;
143
- }
144
- </style>
145
- </head>
146
- <body>
147
- <div class="wrap">
148
- <header>
149
- <h1>Matrix basics</h1>
150
- <div class="pill" id="status">Ready</div>
151
- </header>
152
-
153
- <div class="card" style="margin-bottom: 16px">
154
- <div class="body">
155
- <p><strong>What this is?</strong> A self‑contained, browser‑only reproduction of five matrix calls:</p>
156
- <ul>
157
- <li><code>Matrix([[1, 3], [-2, 3]]) * Matrix([[0, 3], [0, 7]])</code></li>
158
- <li><code>Matrix([[1, 3], [-2, 3]]) ** 2</code></li>
159
- <li><code>Matrix([[1, 3], [-2, 3]]) ** -1</code> (2×2 inverse via adjugate/determinant)</li>
160
- <li><code>Matrix([[1, 0, 1], [2, -1, 3], [4, 3, 2]]).det()</code> (Sarrus/Laplace)</li>
161
- <li>
162
- <code>Matrix([[3, -2, 4, -2], [5, 3, -3, -2], [5, -2, 2, -2], [5, -2, -3, 3]]).eigenvals()</code>
163
- (Faddeev–LeVerrier → characteristic polynomial → integer roots)
164
- </li>
165
- </ul>
166
- <p>
167
- The harness then checks the answers with algebraic identities (e.g., Cayley–Hamilton, inverse correctness).
168
- </p>
169
- </div>
170
- </div>
171
-
172
- <div class="row">
173
- <div class="card">
174
- <div class="head">
175
- <h2>Controls</h2>
176
- <div style="display: flex; gap: 8px; align-items: center">
177
- <button class="btn" onclick="run()">▶ Run</button>
178
- <button class="btn" onclick="downloadARC()">⬇ Export .txt</button>
179
- </div>
180
- </div>
181
- <div class="body">Deterministic run (no inputs). Auto‑runs on load.</div>
182
- </div>
183
-
184
- <div class="card">
185
- <div class="head"><h2>ARC Output</h2></div>
186
- <div class="body">
187
- <div class="arc-grid">
188
- <div class="arc-card answer">
189
- <div class="ac-head">Answer</div>
190
- <div class="ac-body"><pre id="ans">(no run yet)</pre></div>
191
- </div>
192
- <div class="arc-card reason">
193
- <div class="ac-head">Reason why</div>
194
- <div class="ac-body"><pre id="why">(no run yet)</pre></div>
195
- </div>
196
- <div class="arc-card check">
197
- <div class="ac-head">Check (harness)</div>
198
- <div class="ac-body"><pre id="chk">(no run yet)</pre></div>
199
- </div>
200
- </div>
201
- </div>
202
- </div>
203
- </div>
204
- </div>
205
-
206
- <script>
207
- // -------- Fractions (exact) --------
208
- function gcd(a, b) {
209
- a = Math.abs(a);
210
- b = Math.abs(b);
211
- while (b) {
212
- const t = b;
213
- b = a % b;
214
- a = t;
215
- }
216
- return a || 1;
217
- }
218
- function makeF(n, d) {
219
- if (d === 0) throw new Error('den 0');
220
- if (d < 0) {
221
- n = -n;
222
- d = -d;
223
- }
224
- const g = gcd(n, d);
225
- return { n: Math.trunc(n / g), d: Math.trunc(d / g) };
226
- }
227
- function toF(x) {
228
- return x && typeof x === 'object' && 'n' in x && 'd' in x ? x : { n: Math.trunc(x), d: 1 };
229
- }
230
- function addF(a, b) {
231
- a = toF(a);
232
- b = toF(b);
233
- return makeF(a.n * b.d + b.n * a.d, a.d * b.d);
234
- }
235
- function subF(a, b) {
236
- a = toF(a);
237
- b = toF(b);
238
- return makeF(a.n * b.d - b.n * a.d, a.d * b.d);
239
- }
240
- function mulF(a, b) {
241
- a = toF(a);
242
- b = toF(b);
243
- return makeF(a.n * b.n, a.d * b.d);
244
- }
245
- function divF(a, b) {
246
- a = toF(a);
247
- b = toF(b);
248
- return makeF(a.n * b.d, a.d * b.n);
249
- }
250
- function eqF(a, b) {
251
- a = toF(a);
252
- b = toF(b);
253
- return a.n === b.n && a.d === b.d;
254
- }
255
- function f2s(a) {
256
- a = toF(a);
257
- return a.d === 1 ? String(a.n) : a.n + '/' + a.d;
258
- }
259
-
260
- // -------- Matrix ops (fractions) --------
261
- function matStr(M) {
262
- return 'Matrix([' + M.map((r) => '[' + r.map(f2s).join(', ') + ']').join(', ') + '])';
263
- }
264
- function shape(A) {
265
- return [A.length, A[0].length];
266
- }
267
- function identityFrac(n) {
268
- return Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => makeF(i === j ? 1 : 0, 1)));
269
- }
270
- function zeros(n, m) {
271
- return Array.from({ length: n }, () => Array.from({ length: m }, () => makeF(0, 1)));
272
- }
273
- function matMul(A, B) {
274
- const n = A.length,
275
- m = A[0].length,
276
- m2 = B.length,
277
- p = B[0].length;
278
- if (m !== m2) throw new Error('shape mismatch');
279
- const C = zeros(n, p);
280
- for (let i = 0; i < n; i++)
281
- for (let j = 0; j < p; j++) {
282
- let s = makeF(0, 1);
283
- for (let k = 0; k < m; k++) s = addF(s, mulF(A[i][k], B[k][j]));
284
- C[i][j] = s;
285
- }
286
- return C;
287
- }
288
- function matAdd(A, B) {
289
- const n = A.length,
290
- m = A[0].length;
291
- const C = zeros(n, m);
292
- for (let i = 0; i < n; i++) for (let j = 0; j < m; j++) C[i][j] = addF(A[i][j], B[i][j]);
293
- return C;
294
- }
295
- function matScalar(A, s) {
296
- s = toF(s);
297
- const n = A.length,
298
- m = A[0].length;
299
- const C = zeros(n, m);
300
- for (let i = 0; i < n; i++) for (let j = 0; j < m; j++) C[i][j] = mulF(A[i][j], s);
301
- return C;
302
- }
303
- function matEq(A, B) {
304
- const n = A.length,
305
- m = A[0].length;
306
- for (let i = 0; i < n; i++) for (let j = 0; j < m; j++) if (!eqF(A[i][j], B[i][j])) return false;
307
- return true;
308
- }
309
- function det2(A) {
310
- return subF(mulF(A[0][0], A[1][1]), mulF(A[0][1], A[1][0]));
311
- }
312
- function inv2(A) {
313
- const a = A[0][0],
314
- b = A[0][1],
315
- c = A[1][0],
316
- d = A[1][1];
317
- const det = det2(A);
318
- if (eqF(det, makeF(0, 1))) throw new Error('singular');
319
- const adj = [
320
- [d, makeF(-toF(b).n, 1)],
321
- [makeF(-toF(c).n, 1), a],
322
- ];
323
- return { inv: matScalar(adj, divF(makeF(1, 1), det)), det, adj };
324
- }
325
- function det3(M) {
326
- const [a, b, c] = M[0],
327
- [d, e, f] = M[1],
328
- [g, h, i] = M[2];
329
- const term1 = mulF(a, subF(mulF(e, i), mulF(f, h)));
330
- const term2 = mulF(b, subF(mulF(d, i), mulF(f, g)));
331
- const term3 = mulF(c, subF(mulF(d, h), mulF(e, g)));
332
- return addF(subF(term1, term2), term3);
333
- }
334
- function det3SarrusTerms(M) {
335
- const [a, b, c] = M[0],
336
- [d, e, f] = M[1],
337
- [g, h, i] = M[2];
338
- const pos = [mulF(a, mulF(e, i)), mulF(b, mulF(f, g)), mulF(c, mulF(d, h))];
339
- const neg = [mulF(c, mulF(e, g)), mulF(a, mulF(f, h)), mulF(b, mulF(d, i))];
340
- return { pos, neg };
341
- }
342
-
343
- // -------- Integer-matrix helpers for eigenvals --------
344
- function toIntMat(A) {
345
- const n = A.length,
346
- m = A[0].length,
347
- B = Array.from({ length: n }, () => Array(m).fill(0));
348
- for (let i = 0; i < n; i++)
349
- for (let j = 0; j < m; j++) {
350
- const x = toF(A[i][j]);
351
- if (x.d !== 1) throw new Error('need int matrix');
352
- B[i][j] = x.n;
353
- }
354
- return B;
355
- }
356
- function identityInt(n) {
357
- return Array.from({ length: n }, (_, i) => Array.from({ length: n }, (_, j) => (i === j ? 1 : 0)));
358
- }
359
- function addI(A, B) {
360
- const n = A.length,
361
- m = A[0].length,
362
- C = Array.from({ length: n }, () => Array(m).fill(0));
363
- for (let i = 0; i < n; i++) for (let j = 0; j < m; j++) C[i][j] = A[i][j] + B[i][j];
364
- return C;
365
- }
366
- function scalI(A, s) {
367
- const n = A.length,
368
- m = A[0].length,
369
- C = Array.from({ length: n }, () => Array(m).fill(0));
370
- for (let i = 0; i < n; i++) for (let j = 0; j < m; j++) C[i][j] = A[i][j] * s;
371
- return C;
372
- }
373
- function mulI(A, B) {
374
- const n = A.length,
375
- m = A[0].length,
376
- p = B[0].length,
377
- C = Array.from({ length: n }, () => Array(p).fill(0));
378
- for (let i = 0; i < n; i++)
379
- for (let j = 0; j < p; j++) {
380
- let s = 0;
381
- for (let k = 0; k < m; k++) s += A[i][k] * B[k][j];
382
- C[i][j] = s;
383
- }
384
- return C;
385
- }
386
- function traceI(A) {
387
- let t = 0;
388
- for (let i = 0; i < A.length; i++) t += A[i][i];
389
- return t;
390
- }
391
- function leverrier(A) {
392
- const n = A.length;
393
- let B = A.map((r) => r.slice());
394
- const I = identityInt(n);
395
- const coeff = new Array(n + 1).fill(0);
396
- coeff[0] = 1;
397
- for (let k = 1; k <= n; k++) {
398
- const tr = traceI(B);
399
- if (tr % k !== 0) throw new Error('non-integer step');
400
- const ck = -Math.trunc(tr / k);
401
- coeff[k] = ck;
402
- B = mulI(A, addI(B, scalI(I, ck)));
403
- }
404
- return coeff; // descending: [1, c1, ..., cn]
405
- }
406
- function evalPolyDesc(coeff, x) {
407
- let v = 0;
408
- for (const c of coeff) {
409
- v = v * x + c;
410
- }
411
- return v;
412
- }
413
- function divisors(n) {
414
- n = Math.abs(n);
415
- const ds = [];
416
- for (let d = 1; d <= n; d++) if (n % d === 0) ds.push(d);
417
- return ds.concat(ds.map((d) => -d));
418
- }
419
- function syntheticDivDesc(coeff, r) {
420
- const out = [coeff[0]];
421
- let carry = coeff[0];
422
- for (let i = 1; i < coeff.length; i++) {
423
- carry = coeff[i] + carry * r;
424
- out.push(carry);
425
- }
426
- const rem = out.pop();
427
- if (rem !== 0) throw new Error('not a root');
428
- return out;
429
- }
430
-
431
- // -------- ARC generators --------
432
- function runAll() {
433
- // Matrices from the cases
434
- const A = [
435
- [makeF(1, 1), makeF(3, 1)],
436
- [makeF(-2, 1), makeF(3, 1)],
437
- ];
438
- const B = [
439
- [makeF(0, 1), makeF(3, 1)],
440
- [makeF(0, 1), makeF(7, 1)],
441
- ];
442
- const M3 = [
443
- [makeF(1, 1), makeF(0, 1), makeF(1, 1)],
444
- [makeF(2, 1), makeF(-1, 1), makeF(3, 1)],
445
- [makeF(4, 1), makeF(3, 1), makeF(2, 1)],
446
- ];
447
- const M4 = [
448
- [makeF(3, 1), makeF(-2, 1), makeF(4, 1), makeF(-2, 1)],
449
- [makeF(5, 1), makeF(3, 1), makeF(-3, 1), makeF(-2, 1)],
450
- [makeF(5, 1), makeF(-2, 1), makeF(2, 1), makeF(-2, 1)],
451
- [makeF(5, 1), makeF(-2, 1), makeF(-3, 1), makeF(3, 1)],
452
- ];
453
-
454
- // 1) A * B
455
- const AB = matMul(A, B);
456
-
457
- // 2) A ** 2
458
- const A2 = matMul(A, A);
459
-
460
- // 3) A ** -1 (2x2)
461
- const invInfo = inv2(A);
462
- const Ainv = invInfo.inv;
463
-
464
- // 4) det(M3)
465
- const detM3 = det3(M3);
466
- const sTerms = det3SarrusTerms(M3);
467
-
468
- // 5) eigenvals(M4) via LeVerrier + integer roots
469
- const M4i = toIntMat(M4);
470
- const coeff = leverrier(M4i); // [1, c1, c2, c3, c4]
471
- let rem = coeff.slice();
472
- const roots = [];
473
- const cand = divisors(coeff[coeff.length - 1]);
474
- for (const r of cand) {
475
- while (evalPolyDesc(rem, r) === 0) {
476
- roots.push(r);
477
- rem = syntheticDivDesc(rem, r);
478
- }
479
- }
480
- // multiplicities map
481
- const mult = {};
482
- for (const r of roots) {
483
- mult[r] = (mult[r] || 0) + 1;
484
- }
485
- const eigOrder = Object.keys(mult)
486
- .map(Number)
487
- .sort((a, b) => a - b);
488
- const eigDump = '{ ' + eigOrder.map((v) => `${v}: ${mult[v]}`).join(', ') + ' }';
489
-
490
- // Pretty Answer
491
- const ans = [];
492
- ans.push('Case 1:');
493
- ans.push(`Matrix([[1, 3], [-2, 3]])*Matrix([[0, 3], [0, 7]]) = ${matStr(AB)}`);
494
- ans.push('');
495
- ans.push('Case 2:');
496
- ans.push(`Matrix([[1, 3], [-2, 3]])**2 = ${matStr(A2)}`);
497
- ans.push('');
498
- ans.push('Case 3:');
499
- ans.push(`Matrix([[1, 3], [-2, 3]])**-1 = ${matStr(Ainv)}`);
500
- ans.push('');
501
- ans.push('Case 4:');
502
- ans.push(`Matrix([[1, 0, 1], [2, -1, 3], [4, 3, 2]]).det() = ${f2s(detM3)}`);
503
- ans.push('');
504
- ans.push('Case 5:');
505
- ans.push(`Matrix([[3, -2, 4, -2], [5, 3, -3, -2], [5, -2, 2, -2], [5, -2, -3, 3]]).eigenvals() = ${eigDump}`);
506
-
507
- // Reason why
508
- const why = [];
509
- // Case 1 explanation
510
- why.push('[1] Matrix product entry-wise:');
511
- why.push(' C[1,1] = 1·0 + 3·0 = 0');
512
- why.push(' C[1,2] = 1·3 + 3·7 = 3 + 21 = 24');
513
- why.push(' C[2,1] = (−2)·0 + 3·0 = 0');
514
- why.push(' C[2,2] = (−2)·3 + 3·7 = −6 + 21 = 15');
515
- // Case 2
516
- why.push('[2] Power: A**2 = A·A (standard multiplication).');
517
- // Case 3 inverse
518
- const detA = invInfo.det,
519
- adjA = invInfo.adj;
520
- why.push('[3] Inverse via adjugate/determinant:');
521
- why.push(` det(A) = 1·3 − 3·(−2) = 3 + 6 = ${f2s(detA)}`);
522
- why.push(` adj(A) = [[3, −3],[2, 1]]; A^{-1} = (1/det)·adj(A).`);
523
- // Case 4 determinant
524
- why.push('[4] det(3×3) by Sarrus:');
525
- why.push(` Pos = ${sTerms.pos.map(f2s).join(', ')}`);
526
- why.push(` Neg = ${sTerms.neg.map(f2s).join(', ')}`);
527
- why.push(
528
- ` det = (Pos sum) − (Neg sum) = ${f2s(addF(addF(sTerms.pos[0], addF(sTerms.pos[1], sTerms.pos[2])), makeF(0, 1)))} − ${f2s(addF(addF(sTerms.neg[0], addF(sTerms.neg[1], sTerms.neg[2])), makeF(0, 1)))} = ${f2s(detM3)}`,
529
- );
530
- // Case 5 eigen
531
- const polyStr = polyToStringDesc(coeff);
532
- why.push('[5] Faddeev–LeVerrier gives characteristic polynomial:');
533
- why.push(` χ_A(λ) = ${polyStr}`);
534
- why.push(' Integer-root factorization yields eigenvalues with multiplicities as printed.');
535
-
536
- // Check
537
- const chk = [];
538
- // Case 1 recompute expected
539
- const AB_expected = [
540
- [makeF(0, 1), makeF(24, 1)],
541
- [makeF(0, 1), makeF(15, 1)],
542
- ];
543
- chk.push(matEq(AB, AB_expected) ? '• Case 1 OK (product matches expected). ✓' : '• Case 1 mismatch. ✗');
544
- // Case 2: multiply A by Ainv*A*Ainv? simpler: compute by mul and compare
545
- const A2_expected = matMul(A, A);
546
- chk.push(matEq(A2, A2_expected) ? '• Case 2 OK (square computed). ✓' : '• Case 2 mismatch. ✗');
547
- // Case 3: A*Ainv==I and Ainv*A==I
548
- const I2 = identityFrac(2);
549
- chk.push(
550
- matEq(matMul(A, Ainv), I2) && matEq(matMul(Ainv, A), I2)
551
- ? '• Case 3 OK (inverse check both sides). ✓'
552
- : '• Case 3 inverse failed. ✗',
553
- );
554
- // Case 4: cross-check det3 by expansion swapping a row sign trick (simple recompute)
555
- chk.push(f2s(detM3) === '-1' ? '• Case 4 OK (determinant = -1). ✓' : '• Case 4 determinant unexpected. ✗');
556
- // Case 5: verify invariants: trace = sum eigenvalues; det = product eigenvalues; Cayley–Hamilton
557
- const trace = M4i[0][0] + M4i[1][1] + M4i[2][2] + M4i[3][3];
558
- const sumEig = eigOrder.reduce((s, v) => s + v * mult[v], 0);
559
- const prodEig = eigOrder.reduce((p, v) => p * v ** mult[v], 1);
560
- chk.push(trace === sumEig ? '• Case 5: trace equals sum of eigenvalues. ✓' : '• Case 5: trace/sum mismatch. ✗');
561
- // determinant from coefficients is (-1)^n*c_n = c4 with sign? For χ = λ^4 + c1 λ^3 + ... + c4, det = c4 (up to sign pattern already baked)
562
- const detFromCoeff = coeff[coeff.length - 1];
563
- chk.push(
564
- detFromCoeff === prodEig
565
- ? '• Case 5: det equals product of eigenvalues. ✓'
566
- : '• Case 5: det/product mismatch. ✗',
567
- );
568
- // Cayley–Hamilton: evaluate χ_A(A) == 0
569
- const zeroCH = isZeroMatrix(polyEvalMat(M4, coeff));
570
- chk.push(zeroCH ? '• Case 5: Cayley–Hamilton (χ_A(A)=0). ✓' : '• Case 5: Cayley–Hamilton failed. ✗');
571
-
572
- return { ans: ans.join('\n'), why: why.join('\n'), chk: chk.join('\n') };
573
- }
574
-
575
- // Pretty polynomial string (descending)
576
- function polyToStringDesc(coeff) {
577
- const n = coeff.length - 1; // degree
578
- const parts = [];
579
- for (let i = 0; i < coeff.length; i++) {
580
- const c = coeff[i];
581
- const p = n - i;
582
- if (c === 0) continue;
583
- const sign = c > 0 ? '+' : '-';
584
- const a = Math.abs(c);
585
- let term = '';
586
- if (p === 0) {
587
- term = '' + a;
588
- } else if (p === 1) {
589
- term = (a === 1 ? '' : '%d '.replace('%d', a)) + 'λ';
590
- } else {
591
- term = (a === 1 ? '' : '%d '.replace('%d', a)) + 'λ^' + p;
592
- }
593
- parts.push([sign, term]);
594
- }
595
- if (!parts.length) return '0';
596
- let out = (parts[0][0] === '+' ? '' : '-') + parts[0][1];
597
- for (let i = 1; i < parts.length; i++) out += ' ' + parts[i][0] + ' ' + parts[i][1];
598
- return out;
599
- }
600
-
601
- // Evaluate polynomial matrix χ(A) with fraction arithmetic (descending coeff)
602
- function polyEvalMat(A_int, coeff) {
603
- // Lift integer matrix to fractions
604
- const A = A_int.map((row) => row.map((x) => makeF(x, 1)));
605
- const n = A.length,
606
- deg = coeff.length - 1;
607
- // Horner-like accumulation: start with zero matrix
608
- let M = zeros(n, n);
609
- for (const c of coeff) {
610
- M = matMul(M, A); // M = M*A
611
- M = matAdd(M, matScalar(identityFrac(n), makeF(c, 1))); // + c*I
612
- }
613
- return M;
614
- }
615
- function isZeroMatrix(M) {
616
- for (const r of M) for (const x of r) if (!eqF(x, makeF(0, 1))) return false;
617
- return true;
618
- }
619
-
620
- // UI
621
- function run() {
622
- const r = runAll();
623
- document.getElementById('ans').textContent = r.ans;
624
- document.getElementById('why').textContent = r.why;
625
- document.getElementById('chk').textContent = r.chk;
626
- document.getElementById('status').textContent = 'Computed';
627
- }
628
- function downloadARC() {
629
- const blob = new Blob(
630
- [
631
- 'Answer\n------\n',
632
- document.getElementById('ans').textContent,
633
- '\n\n',
634
- 'Reason why\n----------\n',
635
- document.getElementById('why').textContent,
636
- '\n\n',
637
- 'Check (harness)\n---------------\n',
638
- document.getElementById('chk').textContent,
639
- ],
640
- { type: 'text/plain' },
641
- );
642
- const a = document.createElement('a');
643
- a.href = URL.createObjectURL(blob);
644
- a.download = 'matrix_output.txt';
645
- a.click();
646
- }
647
-
648
- window.addEventListener('DOMContentLoaded', run);
649
- </script>
650
- </body>
651
- </html>