``` ### 5b. `docs/love-logic/v3_checks.js` ```js /* Love Logic Proof v3: browser re-implementation of the closed-form checks * in v3_crossover_sim.py (sections B1, B2, B3, B4, C1, C2, D). * Section A (LZMA proxy) has no pass/fail checks in the Python sim and is not re-run here. * Deterministic sections match the Python counts exactly. Monte Carlo sections * (B4, C2) use a seeded mulberry32 stream (seed 20260924), not numpy's PCG64, * so the draws differ from Python; the pass rule (|z| < 4) is the same. * No network, no DOM writes except via textContent in the page glue. * Runs in the browser (window.LoveLogicV3.runAll()) or in Node (node v3_checks.js). * Marker: v-love-logic-proof-v3 */ (function (root) { 'use strict'; var SEED = 20260924; function mulberry32(a) { return function () { a |= 0; a = (a + 0x6D2B79F5) | 0; var t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; } function hazard(n, m, q0, q) { return 1 - Math.pow(1 - q0, n) * Math.pow(1 - q, m * n * (n - 1)); } function lambertw0(z) { if (z < -1 / Math.E - 1e-15) throw new Error('z < -1/e'); if (Math.abs(z + 1 / Math.E) < 1e-14) return -1; var w = z > -0.3 ? Math.log1p(z) : -1 + Math.sqrt(2 * (1 + Math.E * z)); for (var i = 0; i < 200; i++) { var ew = Math.exp(w), f = w * ew - z, wp1 = w + 1; if (Math.abs(wp1) < 1e-300) break; var dw = f / (ew * wp1 - (w + 2) * f / (2 * wp1)); w -= dw; if (Math.abs(dw) < 1e-15 * (1 + Math.abs(w))) break; } return w; } function flows(T, G, c, kappa, h, Lp, Delta, delta) { if (delta === undefined) delta = 1; var out = new Float64Array(T), surv = 1, dpow = 1; for (var d = 0; d < T; d++) { var f = surv * (G - c * kappa * (d + 1) - h * Lp) - (1 - surv) * Delta; out[d] = dpow * f; surv *= (1 - h); dpow *= delta; } return out; } function cumsum(a) { var o = new Float64Array(a.length), s = 0; for (var i = 0; i < a.length; i++) { s += a[i]; o[i] = s; } return o; } function sum(a) { var s = 0; for (var i = 0; i < a.length; i++) s += a[i]; return s; } function Dclosed(t, G, c, kappa, h, Lp, Delta) { if (h === 0) return G * t - c * kappa * t * (t + 1) / 2; var s = 1 - h, A = G - h * Lp + Delta; var geo = (1 - Math.pow(s, t)) / h; var arith = (1 - (t + 1) * Math.pow(s, t) + t * Math.pow(s, t + 1)) / Math.pow(1 - s, 2); return A * geo - c * kappa * arith - Delta * t; } function Dinf(G, c, kappa, h, Lp, Delta, delta) { var x = delta * (1 - h), A = G - h * Lp + Delta; return A / (1 - x) - c * kappa / Math.pow(1 - x, 2) - Delta / (1 - delta); } function firstNegative(cum) { for (var i = 0; i < cum.length; i++) if (cum[i] < -1e-9) return i + 1; return null; } function bisect(f, lo, hi) { var flo = f(lo); for (var i = 0; i < 200; i++) { var mid = 0.5 * (lo + hi), fm = f(mid); if ((fm > 0) === (flo > 0)) { lo = mid; flo = fm; } else { hi = mid; } } return 0.5 * (lo + hi); } function allclose(a, b, rtol, atol) { for (var i = 0; i < a.length; i++) if (Math.abs(a[i] - b[i]) > atol + rtol * Math.abs(b[i])) return false; return true; } function B1() { var ok = 0, tot = 0; [0.5, 1, 2, 5].forEach(function (G) { [0.001, 0.01, 0.05, 0.2].forEach(function (ck) { var tcf = 2 * G / ck - 1, T = Math.floor(tcf) + 50; var tnum = firstNegative(cumsum(flows(T, G, 1, ck, 0, 0, 0))); tot++; if (tnum === Math.floor(tcf) + 1) ok++; var dstar = 1 - ck / G; [0.5, 0.9, 0.99, 0.999].filter(function (d) { return Math.abs(d - dstar) > 1e-3 && d > 0 && d < 1; }) .forEach(function (d) { var num = sum(flows(200000, G, 1, ck, 0, 0, 0, d)); tot++; if ((num < 0) === (d > dstar)) ok++; }); }); }); return { passed: ok, total: tot }; } function B2() { var ok = 0, tot = 0, rows = [], q0 = 0.002, q = 0.01; [2, 5, 10, 20].forEach(function (n) { [0, 0.25, 1].forEach(function (m) { var h = hazard(n, m, q0, q); [[1, 2, 0.5], [3, 5, 1], [0.5, 0, 0.2]].forEach(function (p) { var G = p[0], Lp = p[1], Delta = p[2], A = G - h * Lp + Delta; if (G - h * Lp <= 0) { var c0 = cumsum(flows(50, G, 0, 0, h, Lp, Delta)); tot++; if (c0[0] <= 0) ok++; if (G === 1) rows.push({ n: n, m: m, h: h, never: true }); return; } var a = A / (h * Delta), b = -Math.log(1 - h); var tcf = a + lambertw0(-a * b * Math.exp(-a * b)) / b; var troot = bisect(function (t) { return Dclosed(t, G, 0, 0, h, Lp, Delta); }, 1e-9, 10 * a + 10); var T = Math.floor(tcf) + 200, cum = cumsum(flows(T, G, 0, 0, h, Lp, Delta)); tot++; if (Math.abs(tcf - troot) < 1e-6 * Math.max(1, tcf)) ok++; tot++; if (firstNegative(cum) === Math.floor(tcf) + 1) ok++; var Dcf = new Float64Array(T); for (var t = 1; t <= T; t++) Dcf[t - 1] = Dclosed(t, G, 0, 0, h, Lp, Delta); tot++; if (allclose(Dcf, cum, 1e-9, 1e-9)) ok++; var dstar = (G - h * Lp) / (G - h * Lp + h * Delta); [0.5, 0.8, 0.9, 0.95, 0.99].forEach(function (d) { if (Math.abs(d - dstar) < 1e-4) return; var num = Dinf(G, 0, 0, h, Lp, Delta, d), brute = sum(flows(20000, G, 0, 0, h, Lp, Delta, d)); tot++; if (((num < 0) === (d > dstar)) && Math.abs(num - brute) < 1e-6 * Math.max(1, Math.abs(num))) ok++; }); if (G === 1) rows.push({ n: n, m: m, h: h, tStar: tcf, tPeak: Math.log(A / Delta) / b, deltaStar: dstar }); }); }); }); return { passed: ok, total: tot, rows: rows }; }