eyeling 1.15.11 → 1.15.13

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 (50) hide show
  1. package/README.md +3 -3
  2. package/follows-from/artifacts/ackermann.html +678 -0
  3. package/follows-from/artifacts/auroracare.html +1297 -0
  4. package/follows-from/artifacts/bike-trip.html +752 -0
  5. package/follows-from/artifacts/binomial-theorem.html +631 -0
  6. package/follows-from/artifacts/bmi.html +511 -0
  7. package/follows-from/artifacts/building-performance.html +750 -0
  8. package/follows-from/artifacts/clinical-care.html +726 -0
  9. package/follows-from/artifacts/collatz.html +403 -0
  10. package/follows-from/artifacts/complex.html +321 -0
  11. package/follows-from/artifacts/control-system.html +482 -0
  12. package/follows-from/artifacts/delfour.html +849 -0
  13. package/follows-from/artifacts/earthquake-epicenter.html +982 -0
  14. package/follows-from/artifacts/eco-route.html +662 -0
  15. package/follows-from/artifacts/euclid-infinitude.html +564 -0
  16. package/follows-from/artifacts/euler-identity.html +667 -0
  17. package/follows-from/artifacts/exoplanet-transit.html +1000 -0
  18. package/follows-from/artifacts/faltings-theorem.html +1046 -0
  19. package/follows-from/artifacts/fibonacci.html +299 -0
  20. package/follows-from/artifacts/fundamental-theorem-arithmetic.html +398 -0
  21. package/follows-from/artifacts/godel-numbering.html +743 -0
  22. package/follows-from/artifacts/gps-bike.html +759 -0
  23. package/follows-from/artifacts/gps-clinical-bench.html +792 -0
  24. package/follows-from/artifacts/graph-french.html +449 -0
  25. package/follows-from/artifacts/grass-molecular.html +592 -0
  26. package/follows-from/artifacts/group-theory.html +740 -0
  27. package/follows-from/artifacts/health-info.html +833 -0
  28. package/follows-from/artifacts/kaprekar-constant.html +576 -0
  29. package/follows-from/artifacts/lee.html +805 -0
  30. package/follows-from/artifacts/linked-lists.html +502 -0
  31. package/follows-from/artifacts/lldm.html +612 -0
  32. package/follows-from/artifacts/matrix-multiplication.html +502 -0
  33. package/follows-from/artifacts/matrix.html +651 -0
  34. package/follows-from/artifacts/newton-raphson.html +944 -0
  35. package/follows-from/artifacts/peano-factorial.html +456 -0
  36. package/follows-from/artifacts/pi.html +363 -0
  37. package/follows-from/artifacts/polynomial.html +646 -0
  38. package/follows-from/artifacts/prime.html +366 -0
  39. package/follows-from/artifacts/pythagorean-theorem.html +468 -0
  40. package/follows-from/artifacts/rest-path.html +469 -0
  41. package/follows-from/artifacts/roots-of-unity.html +363 -0
  42. package/follows-from/artifacts/turing.html +409 -0
  43. package/follows-from/artifacts/wind-turbines.html +726 -0
  44. package/follows-from/index.html +549 -0
  45. package/follows-from/library/index.md +22 -0
  46. package/follows-from/logo.svg +12 -0
  47. package/follows-from/manifesto.md +48 -0
  48. package/follows-from/method/index.md +30 -0
  49. package/follows-from/path/index.md +20 -0
  50. package/package.json +4 -3
@@ -0,0 +1,449 @@
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>Graph reachability (French cities)</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
+ --cyan: #06b6d4;
17
+ --indigo: #6366f1;
18
+ --warn: #dc2626;
19
+ --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', monospace;
20
+ --ui:
21
+ system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'Apple Color Emoji',
22
+ 'Segoe UI Emoji';
23
+ }
24
+ html,
25
+ body {
26
+ height: 100%;
27
+ }
28
+ body {
29
+ margin: 0;
30
+ background: var(--bg);
31
+ color: var(--ink);
32
+ font: 15px/1.55 var(--ui);
33
+ }
34
+ .wrap {
35
+ max-width: 980px;
36
+ margin: 28px auto;
37
+ padding: 0 14px;
38
+ }
39
+ header {
40
+ display: flex;
41
+ align-items: center;
42
+ justify-content: space-between;
43
+ margin-bottom: 14px;
44
+ }
45
+ h1 {
46
+ font-size: 20px;
47
+ margin: 0;
48
+ letter-spacing: 0.2px;
49
+ }
50
+ .pill {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ gap: 8px;
54
+ padding: 6px 10px;
55
+ border: 1px solid var(--border);
56
+ border-radius: 999px;
57
+ color: var(--muted);
58
+ background: #fff;
59
+ }
60
+ .card {
61
+ width: 100%;
62
+ background: var(--panel);
63
+ border: 1px solid var(--border);
64
+ border-radius: 14px;
65
+ overflow: hidden;
66
+ margin-bottom: 14px;
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
+ margin: 0;
95
+ }
96
+ button {
97
+ all: unset;
98
+ background: #fff;
99
+ border: 1px solid var(--border);
100
+ padding: 9px 13px;
101
+ border-radius: 10px;
102
+ cursor: pointer;
103
+ }
104
+ button:hover {
105
+ border-color: #cbd5e1;
106
+ }
107
+ .warn {
108
+ color: var(--warn);
109
+ }
110
+ .accent {
111
+ color: var(--accent);
112
+ }
113
+ .btns {
114
+ display: flex;
115
+ gap: 8px;
116
+ flex-wrap: wrap;
117
+ }
118
+ .kv {
119
+ font-family: var(--mono);
120
+ background: #fff;
121
+ border: 1px solid var(--border);
122
+ border-radius: 10px;
123
+ padding: 10px;
124
+ font-size: 13px;
125
+ }
126
+ .muted {
127
+ color: var(--muted);
128
+ }
129
+
130
+ /* ARC boxes with thick colored left borders */
131
+ .arcbox {
132
+ background: #fff;
133
+ border: 1px solid var(--border);
134
+ border-radius: 12px;
135
+ padding: 10px;
136
+ margin: 10px 0;
137
+ }
138
+ .arcbox.answer {
139
+ border-left: 10px solid var(--good);
140
+ }
141
+ .arcbox.reason {
142
+ border-left: 10px solid var(--cyan);
143
+ }
144
+ .arcbox.check {
145
+ border-left: 10px solid var(--indigo);
146
+ }
147
+ .arclabel {
148
+ font-size: 11px;
149
+ text-transform: uppercase;
150
+ letter-spacing: 0.08em;
151
+ color: var(--muted);
152
+ margin-bottom: 6px;
153
+ }
154
+ </style>
155
+ </head>
156
+ <body>
157
+ <div class="wrap">
158
+ <header>
159
+ <h1>Graph reachability</h1>
160
+ <div class="pill" id="status">Ready</div>
161
+ </header>
162
+
163
+ <div class="card">
164
+ <div class="body">
165
+ <p>
166
+ <strong>What this is?</strong> A self‑contained, browser‑only demo that answers the query
167
+ <code>?- path(X, nantes)</code> over a small directed graph of French cities using two Horn clauses:
168
+ </p>
169
+ <pre class="kv">
170
+ C1: path(U,V) :- oneway(U,V).
171
+ C2: path(U,V) :- oneway(U,Z), path(Z,V).</pre
172
+ >
173
+ <p class="muted">
174
+ Answer lists every city X that reaches <code>nantes</code> with one shortest chain. Reason shows a
175
+ backward‑chaining proof for <code>X = paris</code>. Check validates the results by independent forward
176
+ search and shortest‑path minimality.
177
+ </p>
178
+ </div>
179
+ </div>
180
+
181
+ <!-- Vertical layout: all cards stacked -->
182
+ <div class="card">
183
+ <div class="head"><h2>Graph (fixed)</h2></div>
184
+ <div class="body">
185
+ <pre class="kv" id="graphBox"></pre>
186
+ <div class="btns" style="margin-top: 10px">
187
+ <button onclick="run()">▶ Run</button>
188
+ <button onclick="copyARC()">Copy ARC</button>
189
+ <button onclick="downloadTxt()">⬇ Export .txt</button>
190
+ </div>
191
+ </div>
192
+ </div>
193
+
194
+ <div class="card">
195
+ <div class="head"><h2>Query & Goal</h2></div>
196
+ <div class="body">
197
+ <pre class="kv" id="caseBox"></pre>
198
+ </div>
199
+ </div>
200
+
201
+ <div class="card">
202
+ <div class="head">
203
+ <h2>ARC Output</h2>
204
+ <div class="muted">Cards with left borders</div>
205
+ </div>
206
+ <div class="body">
207
+ <div class="arcbox answer">
208
+ <div class="arclabel">Answer</div>
209
+ <pre id="ans">(no run yet)</pre>
210
+ </div>
211
+ <div class="arcbox reason">
212
+ <div class="arclabel">Reason why</div>
213
+ <pre id="why">(no run yet)</pre>
214
+ </div>
215
+ <div class="arcbox check">
216
+ <div class="arclabel">Check (harness)</div>
217
+ <pre id="chk">(no run yet)</pre>
218
+ </div>
219
+ </div>
220
+ </div>
221
+ </div>
222
+
223
+ <script>
224
+ // ----- 0) Data -----
225
+ const EDGES = [
226
+ ['paris', 'orleans'],
227
+ ['paris', 'chartres'],
228
+ ['paris', 'amiens'],
229
+ ['orleans', 'blois'],
230
+ ['orleans', 'bourges'],
231
+ ['blois', 'tours'],
232
+ ['chartres', 'lemans'],
233
+ ['lemans', 'angers'],
234
+ ['lemans', 'tours'],
235
+ ['angers', 'nantes'],
236
+ ];
237
+ const GOAL = 'nantes';
238
+
239
+ // Build succs, preds, nodes
240
+ const oneway = new Set(EDGES.map((e) => JSON.stringify(e)));
241
+ const succs = new Map();
242
+ const preds = new Map();
243
+ const NODES = new Set();
244
+ for (const [u, v] of EDGES) {
245
+ if (!succs.has(u)) succs.set(u, new Set());
246
+ succs.get(u).add(v);
247
+ if (!preds.has(v)) preds.set(v, new Set());
248
+ preds.get(v).add(u);
249
+ NODES.add(u);
250
+ NODES.add(v);
251
+ }
252
+
253
+ // ----- 1) Reverse BFS from goal -----
254
+ function bfsParentsAndDist(goal) {
255
+ const parent = {}; // parent[u] = next hop towards goal
256
+ const dist = { [goal]: 0 };
257
+ const dq = [goal];
258
+ let head = 0;
259
+ while (head < dq.length) {
260
+ const v = dq[head++];
261
+ const Ps = [...(preds.get(v) || [])].sort(); // deterministic
262
+ for (const u of Ps) {
263
+ if (!(u in dist)) {
264
+ dist[u] = dist[v] + 1;
265
+ parent[u] = v;
266
+ dq.push(u);
267
+ }
268
+ }
269
+ }
270
+ return { parent, dist };
271
+ }
272
+ const { parent: PARENT, dist: DIST } = bfsParentsAndDist(GOAL);
273
+ function shortestPath(src, goal) {
274
+ const chain = [src];
275
+ while (chain[chain.length - 1] !== goal) {
276
+ const cur = chain[chain.length - 1];
277
+ chain.push(PARENT[cur]);
278
+ }
279
+ return chain;
280
+ }
281
+
282
+ // ----- 2) Tiny backward chainer (trace only) -----
283
+ function bc_path(u, v, depth, seenEdges, stepCounter) {
284
+ const indent = ' '.repeat(depth);
285
+ logWhy(`${indent}Step ${String(stepCounter()).padStart(2, '0')}: prove path(${u}, ${v})`);
286
+ // C1
287
+ if (oneway.has(JSON.stringify([u, v]))) {
288
+ logWhy(`${indent} ✓ by fact oneway(${u}, ${v})`);
289
+ return true;
290
+ }
291
+ // C2
292
+ const succ = [...(succs.get(u) || [])].sort();
293
+ for (const z of succ) {
294
+ if (seenEdges.has(u + '→' + z)) continue;
295
+ logWhy(`${indent} → try oneway(${u}, ${z}), then prove path(${z}, ${v})`);
296
+ const ok = bc_path(z, v, depth + 1, new Set([...seenEdges, u + '→' + z]), stepCounter);
297
+ if (ok) return true;
298
+ }
299
+ return false;
300
+ }
301
+
302
+ // ----- 3) ARC writers -----
303
+ function setText(id, s) {
304
+ const el = document.getElementById(id);
305
+ if (el) el.textContent = s;
306
+ }
307
+ function status(msg, warn = false) {
308
+ const el = document.getElementById('status');
309
+ if (!el) return;
310
+ el.textContent = msg;
311
+ el.classList.toggle('warn', !!warn);
312
+ }
313
+ let WHY_BUFFER = [];
314
+ function logWhy(line) {
315
+ WHY_BUFFER.push(line);
316
+ }
317
+
318
+ function run() {
319
+ WHY_BUFFER = [];
320
+ // Boxes
321
+ const Gtxt = EDGES.map(([u, v]) => `oneway(${u}, ${v}).`).join('\n');
322
+ setText('graphBox', Gtxt);
323
+ setText(
324
+ 'caseBox',
325
+ `Query : ?- path(X, ${GOAL})
326
+ Goal : ${GOAL}
327
+ Rules : C1, C2 (see above)`,
328
+ );
329
+
330
+ // Answer
331
+ let A = 'Answer\n======\n';
332
+ A += `Query: ?- path(X, ${GOAL})\n\n`;
333
+ const solutions = Object.keys(PARENT).sort();
334
+ if (!solutions.length) {
335
+ A += 'No solutions.';
336
+ } else {
337
+ A += 'All solutions (with one shortest chain each):\n';
338
+ for (const src of solutions) {
339
+ const chain = shortestPath(src, GOAL);
340
+ const hops = chain.length - 1;
341
+ A += ` X = ${src.padEnd(9, ' ')} path: ${chain.join(' → ')} (hops = ${hops})\n`;
342
+ }
343
+ A += `\nTotal solutions: ${solutions.length}`;
344
+ }
345
+ setText('ans', A);
346
+
347
+ // Reason
348
+ let R = '\nReason why\n==========\n';
349
+ R += 'We use two Horn clauses:\n';
350
+ R += ' C1 path(U,V) :- oneway(U,V).\n';
351
+ R += ' C2 path(U,V) :- oneway(U,Z), path(Z,V).\n';
352
+ R += 'Backward-chaining tries C1 (a fact) or applies C2 by choosing a\n';
353
+ R += 'successor Z of U and recursively proving path(Z,V).\n\n';
354
+ const demo_src = 'paris';
355
+ if (!(demo_src in PARENT)) {
356
+ R += `(Demo: ${demo_src} does not reach ${GOAL} in this graph.)`;
357
+ } else {
358
+ R += `Demo proof for X = ${demo_src}:\n`;
359
+ let step = 0;
360
+ const stepper = () => ++step;
361
+ const ok = bc_path(demo_src, GOAL, 0, new Set(), stepper);
362
+ R += WHY_BUFFER.join('\n') + '\n';
363
+ R += ok ? ' ✔ PROVED\n' : ' ✗ NOT PROVED\n';
364
+ R += `Shortest chain: ${shortestPath(demo_src, GOAL).join(' → ')}`;
365
+ }
366
+ setText('why', R);
367
+
368
+ // Check
369
+ let C = '\nCheck (harness)\n===============\n';
370
+ // A) independent forward search from each node
371
+ function reaches_goal_forward(u) {
372
+ if (u === GOAL) return false; // by convention exclude the goal as X
373
+ const seen = new Set([u]);
374
+ const dq = [u];
375
+ let head = 0;
376
+ while (head < dq.length) {
377
+ const x = dq[head++];
378
+ for (const y of succs.get(x) || []) {
379
+ if (y === GOAL) return true;
380
+ if (!seen.has(y)) {
381
+ seen.add(y);
382
+ dq.push(y);
383
+ }
384
+ }
385
+ }
386
+ return false;
387
+ }
388
+ const forward_reach = [...NODES].filter(reaches_goal_forward).sort();
389
+ const solver_reach = Object.keys(PARENT).sort();
390
+ const same = JSON.stringify(forward_reach) === JSON.stringify(solver_reach);
391
+ C += `Forward search nodes == solver nodes ? ${same}\n`;
392
+ if (!same) {
393
+ C += ` forward: ${JSON.stringify(forward_reach)}\n`;
394
+ C += ` solver : ${JSON.stringify(solver_reach)}\n`;
395
+ }
396
+ // B) Validate each shortest path
397
+ function is_valid_chain(chain) {
398
+ for (let i = 0; i < chain.length - 1; i++)
399
+ if (!oneway.has(JSON.stringify([chain[i], chain[i + 1]]))) return false;
400
+ return true;
401
+ }
402
+ let all_valid = true,
403
+ all_minimal = true;
404
+ for (const src of solver_reach) {
405
+ const chain = shortestPath(src, GOAL);
406
+ if (!is_valid_chain(chain)) {
407
+ all_valid = false;
408
+ }
409
+ if (chain.length - 1 !== DIST[src]) {
410
+ all_minimal = false;
411
+ }
412
+ }
413
+ C += `All chains follow oneway edges? ${all_valid}\n`;
414
+ C += `All chains are hop-minimal? ${all_minimal}`;
415
+ setText('chk', C);
416
+
417
+ status('Done');
418
+ }
419
+
420
+ function copyARC() {
421
+ const txt = [
422
+ document.getElementById('ans').textContent,
423
+ document.getElementById('why').textContent,
424
+ document.getElementById('chk').textContent,
425
+ ].join('\n\n');
426
+ navigator.clipboard?.writeText(txt).catch(() => {});
427
+ }
428
+ function downloadTxt() {
429
+ const blob = new Blob(
430
+ [
431
+ document.getElementById('ans').textContent,
432
+ '\n\n',
433
+ document.getElementById('why').textContent,
434
+ '\n\n',
435
+ document.getElementById('chk').textContent,
436
+ ],
437
+ { type: 'text/plain' },
438
+ );
439
+ const a = document.createElement('a');
440
+ a.href = URL.createObjectURL(blob);
441
+ a.download = 'graph_french_output.txt';
442
+ a.click();
443
+ }
444
+
445
+ // auto-run
446
+ window.addEventListener('DOMContentLoaded', run);
447
+ </script>
448
+ </body>
449
+ </html>