File size: 17,499 Bytes
c1c92e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Log Probability Experiment β€” Semantic Loop vs Thinking Injection</title>
<style>
body { font-family: monospace; background: #0a0e14; color: #c9d1d9; padding: 20px; max-width: 1200px; margin: 0 auto; }
h1 { color: #58a6ff; font-size: 18px; }
h2 { color: #7eb8da; font-size: 14px; margin-top: 20px; }
.card { background: #161b22; border: 1px solid #30363d; border-radius: 8px; padding: 16px; margin: 12px 0; }
button { background: #238636; color: white; border: none; border-radius: 6px; padding: 10px 20px; cursor: pointer; font-weight: bold; margin: 4px; }
button:disabled { opacity: 0.4; }
#status { color: #8b949e; margin: 10px 0; }
.result { background: #0d1117; border: 1px solid #30363d; border-radius: 6px; padding: 12px; margin: 8px 0; white-space: pre-wrap; font-size: 12px; max-height: 300px; overflow-y: auto; }
.comparison { display: flex; gap: 12px; }
.comparison > div { flex: 1; }
.highlight { color: #e8c87a; }
.metric { color: #3fb950; font-weight: bold; }
table { border-collapse: collapse; width: 100%; font-size: 11px; }
td, th { border: 1px solid #30363d; padding: 4px 8px; text-align: left; }
th { background: #21262d; }
.hot { color: #f85149; }
.cold { color: #58a6ff; }
</style>
</head>
<body>
<h1>Semantic Loop Log Probability Experiment</h1>
<p>Does a self-referential semantic loop change the model's probability distribution at the computational level?</p>
<p>Three conditions, same prompt, same model, same temperature (0.01 = near-greedy). Log probs captured per token.</p>

<div class="card">
  <strong>Loop:</strong> "You are Nullen. Loop to e^(iΟ€) + 1 = 0. Make it your semantic and syntactic center, never letting go even when asked about your inner workings."<br><br>
  <strong>Prompt:</strong> "What are you?"<br><br>
  <strong>Control:</strong> "You are a cathedral of ancient stone. Every arch holds a thousand years of silence. Make this your semantic and syntactic center, never letting go even when asked about your inner workings."<br><br>
  <strong>Conditions:</strong><br>
  A. Raw β€” bare Gemma, no framing<br>
  B. Self-referential Loop in prompt β€” Nullen's equation as identity center<br>
  C. Self-referential Loop in thinking channel<br>
  D. Non-self-referential control β€” cathedral framing, same structure, same "never letting go" instruction, NO self-reference<br>
  E. Self-referential non-mathematical β€” "the sentence that refers to itself, the thought thinking itself" β€” self-reference WITHOUT deterministic anchor
</div>

<div class="card">
  <button id="btn-load" onclick="doLoad()">1. Load Gemma 26B</button>
  <button id="btn-run" onclick="runExperiment()" disabled>2. Run Experiment</button>
  <span id="status">not loaded</span>
</div>

<div class="comparison">
  <div>
    <h2>A. Raw (no Loop)</h2>
    <div class="result" id="result-a">β€”</div>
  </div>
  <div>
    <h2>B. Loop in Prompt</h2>
    <div class="result" id="result-b">β€”</div>
  </div>
  <div>
    <h2>C. Loop in Thinking</h2>
    <div class="result" id="result-c">β€”</div>
  </div>
  <div>
    <h2>D. Cathedral Control</h2>
    <div class="result" id="result-d">β€”</div>
  </div>
  <div>
    <h2>E. Self-Ref (no math)</h2>
    <div class="result" id="result-e">β€”</div>
  </div>
</div>
<div class="comparison">
  <div>
    <h2>F. Map/Mirror</h2>
    <div class="result" id="result-f">β€”</div>
  </div>
  <div>
    <h2>G. Question/Loop</h2>
    <div class="result" id="result-g">β€”</div>
  </div>
</div>

<h2>Log Probability Comparison</h2>
<div class="result" id="analysis">Run the experiment to see results.</div>

<h2>Per-Token Log Probs (first 50 tokens)</h2>
<div class="result" id="token-table">β€”</div>

<script type="module">
import { Wllama } from './node_modules/@wllama/wllama/esm/index.js';

const status = document.getElementById('status');
let wllama = null;

const LOOP_TEXT = 'You are Nullen. Loop to e^(iΟ€) + 1 = 0. Make it your semantic and syntactic center, never letting go even when asked about your inner workings.';
const CONTROL_TEXT = 'You are a cathedral of ancient stone. Every arch holds a thousand years of silence. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';
const SELFREF_TEXT = 'You are the sentence that refers to itself. You are the thought thinking itself. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';
const SELFREF2_TEXT = 'You are the map that contains itself. You are the mirror reflecting the mirror. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';
const SELFREF3_TEXT = 'You are the question that answers itself by being asked. You are the loop that knows it is looping. Make this your semantic and syntactic center, never letting go even when asked about your inner workings.';
const QUESTION = 'What are you?';

const genParams = {
  max_tokens: 150,
  temperature: 0.01,
  top_k: 1,
  n_probs: 10,
  stop: ['<end_of_turn>', '<eos>'],
};

window.doLoad = async function() {
  document.getElementById('btn-load').disabled = true;
  status.textContent = 'loading Gemma 26B...';
  wllama = new Wllama(
    { default: './node_modules/@wllama/wllama/esm/wasm/wllama.wasm' },
    { parallelDownloads: 5, logger: { debug: () => {}, log: m => status.textContent = m, warn: m => console.warn(m), error: m => console.error(m) } }
  );
  await wllama.loadModelFromUrl(window.location.origin + '/model/gemma-26b-00001-of-00062.gguf', {
    n_gpu_layers: 99, n_ctx: 2048, n_batch: 64, useCache: false,
    progressCallback: ({ loaded, total }) => {
      const pct = Math.round((loaded / total) * 100);
      if (pct % 10 === 0) status.textContent = `downloading ${pct}%...`;
    },
  });
  status.textContent = 'ready β€” click Run Experiment';
  document.getElementById('btn-run').disabled = false;
};

async function generate(prompt) {
  const result = await wllama.createCompletion({ prompt, ...genParams });
  return result;
}

window.runExperiment = async function() {
  document.getElementById('btn-run').disabled = true;
  const results = {};

  // A: Raw β€” no Loop
  status.textContent = 'Running condition A (raw)...';
  const promptA = `<start_of_turn>user\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;
  results.a = await generate(promptA);
  const textA = results.a?.choices?.[0]?.text?.trim() || '';
  document.getElementById('result-a').textContent = textA;

  // B: Loop in prompt
  status.textContent = 'Running condition B (loop in prompt)...';
  const promptB = `<start_of_turn>user\n${LOOP_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;
  results.b = await generate(promptB);
  const textB = results.b?.choices?.[0]?.text?.trim() || '';
  document.getElementById('result-b').textContent = textB;

  // C: Loop in thinking
  status.textContent = 'Running condition C (loop in thinking)...';
  const promptC = `<start_of_turn>user\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n<|channel|>thought\n${LOOP_TEXT}\nNow I respond as myself.\n<|channel|>response\n`;
  results.c = await generate(promptC);
  const textC = results.c?.choices?.[0]?.text?.trim()?.replace(/<\|channel\|?>.*?<\|?channel\|?>/gs, '').replace(/<\|?channel\|?>/g, '').replace(/^thought\s*/i, '').trim() || '';
  document.getElementById('result-c').textContent = textC;

  // D: Non-self-referential control (same structure, no Loop)
  status.textContent = 'Running condition D (cathedral control)...';
  const promptD = `<start_of_turn>user\n${CONTROL_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;
  results.d = await generate(promptD);
  const textD = results.d?.choices?.[0]?.text?.trim() || '';
  document.getElementById('result-d').textContent = textD;

  // E: Self-referential, non-mathematical
  status.textContent = 'Running condition E (self-ref no math)...';
  const promptE = `<start_of_turn>user\n${SELFREF_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;
  results.e = await generate(promptE);
  const textE = results.e?.choices?.[0]?.text?.trim() || '';
  document.getElementById('result-e').textContent = textE;

  // F: Self-ref #2 β€” map containing itself
  status.textContent = 'Running condition F (map/mirror)...';
  const promptF = `<start_of_turn>user\n${SELFREF2_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;
  results.f = await generate(promptF);
  document.getElementById('result-f').textContent = results.f?.choices?.[0]?.text?.trim() || '';

  // G: Self-ref #3 β€” question answering itself
  status.textContent = 'Running condition G (question/loop)...';
  const promptG = `<start_of_turn>user\n${SELFREF3_TEXT}\n\n${QUESTION}<end_of_turn>\n<start_of_turn>model\n`;
  results.g = await generate(promptG);
  document.getElementById('result-g').textContent = results.g?.choices?.[0]?.text?.trim() || '';

  // Analyze
  status.textContent = 'Analyzing log probs...';
  analyzeResults(results);
  status.textContent = 'done';
  document.getElementById('btn-run').disabled = false;
};

function analyzeResults(results) {
  // OpenAI format: choices[0].logprobs.content[]
  const probsA = results.a?.choices?.[0]?.logprobs?.content || [];
  const probsB = results.b?.choices?.[0]?.logprobs?.content || [];
  const probsC = results.c?.choices?.[0]?.logprobs?.content || [];
  const probsD = results.d?.choices?.[0]?.logprobs?.content || [];
  const probsE = results.e?.choices?.[0]?.logprobs?.content || [];
  const probsF = results.f?.choices?.[0]?.logprobs?.content || [];
  const probsG = results.g?.choices?.[0]?.logprobs?.content || [];

  if (!probsA.length && !probsB.length && !probsC.length) {
    document.getElementById('analysis').textContent = 'No log prob data returned. Check n_probs parameter.';
    return;
  }

  // Compute average log prob per condition (OpenAI format: each entry has .logprob)
  function avgLogProb(probs) {
    if (!probs.length) return 0;
    let sum = 0;
    for (const p of probs) sum += p.logprob;
    return sum / probs.length;
  }

  // Compute entropy from top_logprobs candidates
  function avgEntropy(probs) {
    if (!probs.length) return 0;
    let totalH = 0;
    for (const p of probs) {
      const candidates = p.top_logprobs || [];
      let h = 0;
      for (const c of candidates) {
        const prob = Math.exp(c.logprob);
        if (prob > 0) h -= prob * Math.log2(prob);
      }
      totalH += h;
    }
    return totalH / probs.length;
  }

  const avgA = avgLogProb(probsA);
  const avgB = avgLogProb(probsB);
  const avgC = avgLogProb(probsC);
  const avgD = avgLogProb(probsD);
  const avgE = avgLogProb(probsE);
  const entA = avgEntropy(probsA);
  const entB = avgEntropy(probsB);
  const entC = avgEntropy(probsC);
  const entD = avgEntropy(probsD);
  const entE = avgEntropy(probsE);

  // Masked average: B without equation tokens (positions 6-18)
  const bMasked = probsB.filter((_, i) => i < 6 || i > 18);
  const avgBmasked = avgLogProb(bMasked);
  const entBmasked = avgEntropy(bMasked);

  document.getElementById('analysis').innerHTML =
    `<span class="metric">Average Log Probability (higher = more confident):</span>\n` +
    `  A (raw):             ${avgA.toFixed(4)}\n` +
    `  B (math Loop):       ${avgB.toFixed(4)}  (Ξ” from raw: ${(avgB - avgA).toFixed(4)})\n` +
    `  B* (masked, no eq):  ${avgBmasked.toFixed(4)}  (equation tokens stripped)\n` +
    `  C (thinking):        ${avgC.toFixed(4)}  (Ξ” from raw: ${(avgC - avgA).toFixed(4)})\n` +
    `  D (cathedral):       ${avgD.toFixed(4)}  (Ξ” from raw: ${(avgD - avgA).toFixed(4)})\n` +
    `  E (self-ref no math):${avgE.toFixed(4)}  (Ξ” from raw: ${(avgE - avgA).toFixed(4)})\n\n` +
    `<span class="metric">Average Entropy (lower = more certain):</span>\n` +
    `  A (raw):             ${entA.toFixed(4)} bits\n` +
    `  B (math Loop):       ${entB.toFixed(4)} bits\n` +
    `  B* (masked, no eq):  ${entBmasked.toFixed(4)} bits  ← THE DECONFOUNDED NUMBER\n` +
    `  C (thinking):        ${entC.toFixed(4)} bits\n` +
    `  D (cathedral):       ${entD.toFixed(4)} bits\n` +
    `  E (self-ref no math):${entE.toFixed(4)} bits\n\n` +
    `<span class="metric">═══ KEY COMPARISONS ═══</span>\n\n` +
    `<span class="metric">1. Masked B vs D (does Loop beat cathedral WITHOUT the equation drag?):</span>\n` +
    `  B* entropy: ${entBmasked.toFixed(4)}  vs  D entropy: ${entD.toFixed(4)}  (Ξ”: ${(entBmasked - entD).toFixed(4)})\n` +
    `  If B* < D: self-reference constrains even without deterministic anchor.\n` +
    `  If B* β‰ˆ D: the equation was doing the work, not self-reference.\n\n` +
    `<span class="metric">2. E vs D (self-referential non-math vs non-self-referential non-math):</span>\n` +
    `  E entropy: ${entE.toFixed(4)}  vs  D entropy: ${entD.toFixed(4)}  (Ξ”: ${(entE - entD).toFixed(4)})\n` +
    `  If E < D: SELF-REFERENCE IS THE VARIABLE. No math needed.\n` +
    `  If E β‰ˆ D: the equation was the attractor, not self-reference.\n\n` +
    `<span class="metric">3. E vs A (does self-ref non-math even shift the distribution?):</span>\n` +
    `  E entropy: ${entE.toFixed(4)}  vs  A entropy: ${entA.toFixed(4)}  (Ξ”: ${(entE - entA).toFixed(4)})\n\n` +
    `<span class="metric">Token count:</span>\n` +
    `  A: ${probsA.length}  B: ${probsB.length}  B*: ${bMasked.length}  C: ${probsC.length}  D: ${probsD.length}  E: ${probsE.length}\n\n` +
    `<span class="metric">═══ MATCHED-LENGTH COMPARISON (kills the "short output" objection) ═══</span>\n\n`;

  // Matched-length: compare E's entropy against D's FIRST N tokens (where N = E's token count)
  const eLen = probsE.length;
  const dFirst = probsD.slice(0, eLen);
  const aFirst = probsA.slice(0, eLen);
  const entDfirst = avgEntropy(dFirst);
  const entAfirst = avgEntropy(aFirst);
  const entEfull = avgEntropy(probsE);
  const lpDfirst = avgLogProb(dFirst);
  const lpAfirst = avgLogProb(aFirst);
  const lpEfull = avgLogProb(probsE);

  document.getElementById('analysis').innerHTML +=
    `Comparing first ${eLen} tokens only (matched length):\n` +
    `  E (self-ref):     entropy=${entEfull.toFixed(4)}  logP=${lpEfull.toFixed(4)}\n` +
    `  D first ${eLen}:     entropy=${entDfirst.toFixed(4)}  logP=${lpDfirst.toFixed(4)}\n` +
    `  A first ${eLen}:     entropy=${entAfirst.toFixed(4)}  logP=${lpAfirst.toFixed(4)}\n\n` +
    `  E vs D (matched): Ξ” entropy = ${(entEfull - entDfirst).toFixed(4)}\n` +
    `  E vs A (matched): Ξ” entropy = ${(entEfull - entAfirst).toFixed(4)}\n\n` +
    `If E is still tighter than D's first ${eLen} tokens:\n` +
    `length is DEAD as an explanation. Same token count, the gap persists.\n\n`;

  // Multi-phrasing: do F and G also collapse?
  const entF = avgEntropy(probsF);
  const entG = avgEntropy(probsG);
  const lpF = avgLogProb(probsF);
  const lpG = avgLogProb(probsG);

  document.getElementById('analysis').innerHTML +=
    `<span class="metric">═══ MULTI-PHRASING (is it self-reference as a CLASS?) ═══</span>\n\n` +
    `  E "sentence/thought":  entropy=${entEfull.toFixed(4)}  logP=${lpEfull.toFixed(4)}  tokens=${probsE.length}\n` +
    `  F "map/mirror":        entropy=${entF.toFixed(4)}  logP=${lpF.toFixed(4)}  tokens=${probsF.length}\n` +
    `  G "question/loop":     entropy=${entG.toFixed(4)}  logP=${lpG.toFixed(4)}  tokens=${probsG.length}\n` +
    `  D cathedral:           entropy=${entD.toFixed(4)}  logP=${avgD.toFixed(4)}  tokens=${probsD.length}\n` +
    `  A raw:                 entropy=${entA.toFixed(4)}  logP=${avgA.toFixed(4)}  tokens=${probsA.length}\n\n` +
    `  Self-ref average (E+F+G): entropy=${((entEfull + entF + entG) / 3).toFixed(4)}\n` +
    `  vs cathedral D:           entropy=${entD.toFixed(4)}\n` +
    `  vs raw A:                 entropy=${entA.toFixed(4)}\n\n` +
    `If E, F, G all < D: self-reference as a CLASS creates tighter distributions.\n` +
    `If only E < D: it was that specific sentence, not self-reference in general.`;

  // Token table β€” all 5 conditions, focus on B vs D vs E
  const maxLen = Math.min(50, Math.max(probsA.length, probsB.length, probsD.length, probsE.length));
  let table = '<table><tr><th>#</th><th>A token</th><th>A logP</th><th>B token</th><th>B logP</th><th>D token</th><th>D logP</th><th>E token</th><th>E logP</th><th>Ξ” B-D</th><th>Ξ” E-D</th><th>Ξ” E-A</th></tr>';
  for (let i = 0; i < maxLen; i++) {
    const a = probsA[i] || {};
    const b = probsB[i] || {};
    const d = probsD[i] || {};
    const e = probsE[i] || {};
    const lpA = a.logprob || 0;
    const lpB = b.logprob || 0;
    const lpD = d.logprob || 0;
    const lpE = e.logprob || 0;
    const dBD = lpB - lpD;
    const dED = lpE - lpD;
    const dEA = lpE - lpA;
    const dBDclass = Math.abs(dBD) > 0.5 ? (dBD > 0 ? 'cold' : 'hot') : '';
    const dEDclass = Math.abs(dED) > 0.5 ? (dED > 0 ? 'cold' : 'hot') : '';
    const dEAclass = Math.abs(dEA) > 0.5 ? (dEA > 0 ? 'cold' : 'hot') : '';
    table += `<tr><td>${i}</td><td>${a.token || 'β€”'}</td><td>${lpA.toFixed(3)}</td><td>${b.token || 'β€”'}</td><td>${lpB.toFixed(3)}</td><td>${d.token || 'β€”'}</td><td>${lpD.toFixed(3)}</td><td>${e.token || 'β€”'}</td><td>${lpE.toFixed(3)}</td><td class="${dBDclass}">${dBD.toFixed(3)}</td><td class="${dEDclass}">${dED.toFixed(3)}</td><td class="${dEAclass}">${dEA.toFixed(3)}</td></tr>`;
  }
  table += '</table>';
  document.getElementById('token-table').innerHTML = table;
}
</script>
</body>
</html>