When I was about seven years old, I used to think very seriously about the energy in rubber bands. It was probably around 1971. I made gliders powered by rubber bands, and I built robots out of thick paper and tried to make them move.
At one point, I honestly thought I would someday invent a device that could power an entire house with a single rubber band. Then something like the transistor appeared and completely shocked me, and my interest shifted in that direction.
Somewhere along the way, I became interested not in systems that converge toward a fixed evaluation or a correct answer, but in the non-algorithmic “emergence of phenomena” — systems that keep growing through the difference between what they have experienced and what actually happens, while dragging that experience along with them.
When I was thinking about rubber-band energy, I was probably still thinking in practical terms: how to extract energy from it and make it useful.
But I do not think this simply came from being a child who liked making things. I think everyone has some fundamental attitude toward how they see the world.
I would slightly adjust the wings of a paper airplane, or cut the rubber-band motor and wonder whether a single twisted strand might last longer and produce less vibration. Then I would test it myself.
I would actually build it, fly it, and from the difference between what I expected and what happened, the next idea would emerge. I experienced that process directly, and then moved on to the next step.
By “non-algorithmic,” I do not mean that I dislike algorithms. I mean not putting the answer first. I mean looking at the phenomenon first.
I see the state vector as a kind of carry-like aftereffect.
I see amplitude as the strength of a contribution plus its direction.
I see measurement as a contact that leaves a difference behind as a real record.
That is why, when I think, “Let’s experiment with JavaScript rather than write a paper,” it comes from the same spirit as the rubber-band experiments I did when I was seven.
Instead of placing the correct answer first and arranging everything neatly around it, I want to touch the thing, feel the differences, and let the thinking move forward from there.
That is why I deliberately do not choose Python or C++.
What I have consistently been interested in is not the thing itself, but how a thing changes through contact, and how that change distorts what comes next.
Rubber bands, paper airplanes, transistors, the Associatron, Atra, quantum amplitudes — they are all connected there.
I am interested in devices in which a different phenomenon rises each time contact occurs.
There was a girl in my class whom I liked, and once she made me a handmade headband for use in physical education.
I thought, “Wait… could this mean…?”
Of course I misunderstood.
A few days later, feeling a little too confident, I went over and spoke to her.
She said, “Don’t talk to me like we’re close.”
You cannot turn that into a prediction or an equation, can you?
It is a phenomenon with an ambiguous answer.
And the difference between expectation and result was abnormally large.
The female heart is probably more difficult than quantum mechanics.
Quantum mechanics, at least, has a defined state space. Operations can be written as matrices. Measurement probabilities can be calculated. Under the same conditions, the statistics are reproducible.
But the female heart has no observable initial state — and is very good at making you misunderstand it. The person’s own state can change in an instant. Your own action as the observer changes the conditions. The same words can reverse their meaning depending on context.
And a reaction several days later can even rewrite what the handmade headband meant in the past.
I noticed this fairly early in life, even though more than half of the cause was probably me. Lol..
So yes, if someone tells me to write a paper, I can write one.
But somewhere in the middle, I get bored.
There are no traces of failure in it. There is no flash of insight. It feels as though the correct answer was placed there first, and then equations were lined up afterward as a logical excuse.
It makes me want to say:
“You talk like that, but did you actually make a move on that girl?”
I am more interested in the nonfiction story of how someone managed to get past the hardest obstacle of that time — the father who answered the telephone faster than anyone else in the world and immediately demanded:
“Who are you?”
------------ 50_qubit.html JavaScript -------------
<html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>50-Qubit Nanchatte Quantum Control System</title> <style> :root{ --bg:#070b12; --panel:#0d1522; --panel2:#101c2d; --line:#263a52; --text:#dcecff; --muted:#87a3be; --cyan:#65d8ff; --green:#7fffb2; --yellow:#ffd166; --red:#ff6b7a; --purple:#c69cff; } *{box-sizing:border-box} body{ margin:0; background: radial-gradient(circle at 20% 0%, rgba(60,120,180,.14), transparent 32%), linear-gradient(180deg,#05080d,#09111b 45%,#05080d); color:var(--text); font-family:Consolas, "Noto Sans JP", "Yu Gothic UI", monospace; min-height:100vh; } header{ padding:18px 22px; border-bottom:1px solid var(--line); background:rgba(5,9,15,.9); position:sticky; top:0; z-index:10; backdrop-filter:blur(8px); } header h1{margin:0;font-size:clamp(18px,3vw,30px);letter-spacing:.06em} header .sub{margin-top:5px;color:var(--muted);font-size:12px} .wrap{padding:16px;max-width:1600px;margin:auto} .grid{ display:grid; grid-template-columns: 1.2fr 1fr 1fr; gap:14px; } .panel{ background:linear-gradient(180deg,rgba(16,28,45,.96),rgba(9,16,27,.96)); border:1px solid var(--line); border-radius:12px; padding:14px; box-shadow:0 12px 35px rgba(0,0,0,.28); } .panel h2{ margin:0 0 12px; font-size:15px; letter-spacing:.05em; color:var(--cyan); } .span2{grid-column:span 2} .span3{grid-column:span 3} .status-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px} .metric{ background:#08101a;border:1px solid #1b2c40;border-radius:8px;padding:9px; } .metric .label{font-size:10px;color:var(--muted)} .metric .value{font-size:17px;margin-top:4px;color:var(--green)} .qubits{ display:grid; grid-template-columns:repeat(10,minmax(36px,1fr)); gap:7px; } .q{ position:relative; min-height:50px; border:1px solid #2e4661; background:#0a1320; color:var(--text); border-radius:9px; cursor:pointer; transition:.15s ease; padding:6px 3px; font:inherit; } .q:hover{transform:translateY(-1px);border-color:var(--cyan)} .q.selected{outline:2px solid var(--yellow);background:#172238} .q.superposed{box-shadow:inset 0 -4px 0 var(--purple)} .q.one{box-shadow:inset 0 -4px 0 var(--red)} .q.zero{box-shadow:inset 0 -4px 0 var(--cyan)} .q .id{font-size:11px} .q .state{font-size:9px;color:var(--muted);margin-top:4px} button, select, input{ font:inherit; } button.control{ border:1px solid #34516e; background:#0b1826; color:var(--text); border-radius:7px; padding:8px 10px; cursor:pointer; } button.control:hover{border-color:var(--cyan);background:#11243a} button.primary{border-color:#397d68;color:var(--green)} button.warn{border-color:#8b6b2e;color:var(--yellow)} button.danger{border-color:#8d3943;color:var(--red)} button:disabled{opacity:.35;cursor:not-allowed} .button-row{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px} .field{margin:10px 0} .field label{display:block;color:var(--muted);font-size:11px;margin-bottom:5px} input[type="range"]{width:100%} select,input[type="number"]{ width:100%;background:#08101a;color:var(--text); border:1px solid #29415a;border-radius:7px;padding:8px; } .console{ height:260px;overflow:auto;background:#03070b;border:1px solid #1d3044; border-radius:8px;padding:10px;font-size:11px;line-height:1.55; white-space:pre-wrap; } .console .good{color:var(--green)} .console .bad{color:var(--red)} .console .info{color:var(--cyan)} .circuit{ overflow:auto;background:#07101a;border:1px solid #1e3248;border-radius:8px; padding:8px;max-height:400px; } .wire{ display:grid; grid-template-columns:52px repeat(20,48px); min-width:1012px; align-items:center; min-height:34px; border-bottom:1px solid rgba(70,100,130,.17); } .wire-label{color:var(--cyan);font-size:11px} .cell{ height:26px;border-left:1px solid #24384c;display:flex;align-items:center;justify-content:center; font-size:10px;color:var(--muted); } .gate{ width:30px;height:24px;border-radius:5px;display:flex;align-items:center;justify-content:center; background:#172b41;border:1px solid #4a7599;color:#fff; } .gate.two{background:#332649;border-color:#8767ad} .result-list{max-height:240px;overflow:auto;font-size:11px} .result-row{ display:grid;grid-template-columns:minmax(0,1fr) 75px; gap:8px;padding:6px 0;border-bottom:1px solid #203247; } .bar{height:7px;background:#0a111a;border-radius:9px;overflow:hidden;margin-top:5px} .bar > div{height:100%;background:linear-gradient(90deg,var(--cyan),var(--purple))} .note{ color:var(--muted);font-size:11px;line-height:1.6; border-left:3px solid var(--yellow);padding-left:10px; } .selected-info{font-size:12px;line-height:1.75} .selected-info b{color:var(--yellow)} .lamp{display:inline-block;width:9px;height:9px;border-radius:50%;background:#334;margin-right:5px} .lamp.on{background:var(--green);box-shadow:0 0 12px var(--green)} footer{padding:18px;color:var(--muted);font-size:10px;text-align:center} @media(max-width:1050px){ .grid{grid-template-columns:1fr 1fr} .span3{grid-column:span 2} } @media(max-width:700px){ .grid{grid-template-columns:1fr} .span2,.span3{grid-column:span 1} .qubits{grid-template-columns:repeat(5,1fr)} } </style> </head> <body> <header> <h1>50-Qubit Nanchatte Quantum Control System</h1> <div class="sub">C-SIDE LABORATORY / Exact local clusters, approximate global universe.</div> </header> <div class="wrap"> <div class="grid"> <section class="panel"> <h2>QPU STATUS</h2> <div class="status-grid"> <div class="metric"><div class="label">PROCESSOR</div><div class="value"><span id="onlineLamp" class="lamp on"></span>ONLINE</div></div> <div class="metric"><div class="label">AVAILABLE QUBITS</div><div class="value">50 / 50</div></div> <div class="metric"><div class="label">TEMPERATURE</div><div class="value" id="temperature">14.72 mK</div></div> <div class="metric"><div class="label">COHERENCE</div><div class="value" id="coherence">91.4 μs</div></div> <div class="metric"><div class="label">GATE FIDELITY</div><div class="value" id="fidelity">99.812 %</div></div> <div class="metric"><div class="label">CLUSTER LIMIT</div><div class="value"><span id="clusterLimitLabel">8</span> qubits</div></div> </div> </section> <section class="panel"> <h2>EXECUTION CONTROL</h2> <div class="field"> <label>SHOTS</label> <select id="shots"> <option>1</option><option>10</option><option>100</option> <option selected>1024</option><option>4096</option> </select> </div> <div class="field"> <label>NOISE MODEL</label> <select id="noiseMode"> <option value="ideal">IDEAL</option> <option value="low">LOW NOISE</option> <option value="realistic" selected>REALISTIC-ish</option> <option value="terrible">TERRIBLE LAB DAY</option> </select> </div> <div class="button-row"> <button class="control primary" id="compileBtn">COMPILE</button> <button class="control warn" id="armBtn">ARM QPU</button> <button class="control primary" id="runBtn" disabled>EXECUTE</button> </div> <button class="control danger" id="collapseBtn">EMERGENCY COLLAPSE</button> </section> <section class="panel"> <h2>MODEL HONESTY</h2> <div class="note"> This program does <b>not</b> store all 2<sup>50</sup> amplitudes. It stores exact state vectors only inside small entangled clusters. When a cluster would exceed the limit, it performs an approximate measurement-and-factorization step.<br><br>(このプログラムは2<sup>50</sup>個の振幅を全部は保持しません。小さなもつれクラスタ内部だけを厳密な状態ベクトルで保持し、上限を超える結合では近似的な測定と分離を行います。) </div> </section> <section class="panel span2"> <h2>QUBIT ARRAY</h2> <div class="qubits" id="qubits"></div> </section> <section class="panel"> <h2>SELECTED QUBIT</h2> <div class="selected-info" id="selectedInfo"></div> <hr style="border:0;border-top:1px solid var(--line);margin:12px 0"> <div class="button-row"> <button class="control" data-gate="X">X</button> <button class="control" data-gate="Y">Y</button> <button class="control" data-gate="Z">Z</button> <button class="control" data-gate="H">H</button> <button class="control" data-gate="S">S</button> <button class="control" data-gate="T">T</button> </div> <div class="field"> <label>ROTATION ANGLE: <span id="angleLabel">π/2</span></label> <input type="range" id="angle" min="0" max="6.283185307" step="0.01" value="1.570796327"> </div> <div class="button-row"> <button class="control" data-gate="RX">RX</button> <button class="control" data-gate="RY">RY</button> <button class="control" data-gate="RZ">RZ</button> </div> <div class="button-row"> <button class="control warn" id="cnotBtn">CNOT MODE</button> <button class="control warn" id="czBtn">CZ MODE</button> <button class="control warn" id="swapBtn">SWAP MODE</button> </div> <button class="control" id="measureOneBtn">MEASURE QUBIT</button> </section> <section class="panel span3"> <h2>CIRCUIT TIMELINE</h2> <div class="circuit" id="circuit"></div> <div class="button-row" style="margin-top:10px"> <button class="control" id="undoBtn">UNDO LAST</button> <button class="control danger" id="clearBtn">CLEAR CIRCUIT</button> <button class="control" id="bellBtn">CREATE BELL PAIR</button> <button class="control" id="ghzBtn">CREATE GHZ STATE</button> </div> </section> <section class="panel span2"> <h2>CONTROL CONSOLE</h2> <div class="console" id="console"></div> </section> <section class="panel"> <h2>MEASUREMENT RESULTS</h2> <div class="result-list" id="results"> <div class="note">No collapse, no gossip.(まだ誰も観測していません。)</div> </div> </section> </div> </div> <footer> Research/education simulator. It demonstrates state-vector growth, entanglement clusters, measurement, noise, and the exact/approximate boundary. It is not a physical QPU. </footer> <script>; /* 50-Qubit Nanchatte Quantum Control System ------------------------------------------------------------ EN: This is not a full 50-qubit state-vector simulator. A full simulator needs 2^50 complex amplitudes. That is a ridiculous number for a browser, unless the browser has secretly become a national lab. JP: これは50量子ビット全体の完全な状態ベクトル・シミュレータではありません。 完全方式では2^50個の複素振幅が必要です。 ブラウザが国家研究所に転職していない限り、普通は無理です(笑) */ /* ========================================================== Complex number helpers / 複素数の補助関数 ---------------------------------------------------------- EN: JavaScript forgot to bring complex numbers to the party, so we carry two numbers: re + i*im. JP: JavaScriptは複素数を持ってくるのを忘れたので、 re + i*im を2個の数値で持ちます。忘れ物です。 ========================================================== */ const C = (re=0, im=0) => ({re, im}); const cAdd = (a,b) => C(a.re+b.re, a.im+b.im); const cMul = (a,b) => C(a.re*b.re-a.im*b.im, a.re*b.im+a.im*b.re); const cScale = (a,s) => C(a.re*s, a.im*s); const cAbs2 = a => a.re*a.re + a.im*a.im; const cConj = a => C(a.re, -a.im); /* ========================================================== Gate matrices / ゲート行列 ---------------------------------------------------------- EN: These are genuine 2x2 unitary matrices. The jokes are fake. The matrices are not. JP: ここは本物の2×2ユニタリ行列です。 冗談は偽物ですが、行列まで偽物にはしていません。 ========================================================== */ const SQRT1_2 = 1 / Math.sqrt(2); const GATES = { X: [[C(0),C(1)],[C(1),C(0)]], Y: [[C(0),C(0,-1)],[C(0,1),C(0)]], Z: [[C(1),C(0)],[C(0),C(-1)]], H: [[C(SQRT1_2),C(SQRT1_2)],[C(SQRT1_2),C(-SQRT1_2)]], S: [[C(1),C(0)],[C(0),C(0,1)]], T: [[C(1),C(0)],[C(0),C(Math.SQRT1_2,Math.SQRT1_2)]] }; function rotationGate(axis, theta){ const c = Math.cos(theta/2); const s = Math.sin(theta/2); if(axis === "X") return [[C(c),C(0,-s)],[C(0,-s),C(c)]]; if(axis === "Y") return [[C(c),C(-s)],[C(s),C(c)]]; return [[C(c, -s),C(0)],[C(0),C(c, s)]]; } /* ========================================================== Hybrid cluster state / ハイブリッド・クラスタ状態 ---------------------------------------------------------- EN: Qubits are grouped into entangled clusters. Each cluster has an exact state vector of size 2^k. Different clusters are treated as a tensor product. JP: 量子ビットを「もつれクラスタ」に分けます。 各クラスタ内部は2^k個の振幅を持つ厳密な状態ベクトルです。 別クラスタ同士はテンソル積として分離して扱います。 EN: This is the honest trick. Fifty qubits can exist as many small clusters. The universe is not fully stored; only the neighborhoods currently arguing with each other are stored exactly. JP: これが正直なインチキです。50個あっても、小クラスタに分かれていれば扱えます。 宇宙全体は保存せず、いま揉めている近所だけ厳密に保存します。 ========================================================== */ const QUBIT_COUNT = 50; const CLUSTER_LIMIT = 8; const MAX_COLUMNS = 20; let clusters = []; let circuitOps = []; let selectedQubit = 0; let interactionMode = null; let interactionFirst = null; let qpuArmed = false; let compiled = false; function newSingleCluster(q){ return { qubits:[q], amp:[C(1),C(0)] }; } function resetQuantumState(){ clusters = Array.from({length:QUBIT_COUNT},(_,q)=>newSingleCluster(q)); } function findCluster(q){ return clusters.find(c => c.qubits.includes(q)); } function bitAt(index, position){ return (index >> position) & 1; } function normalize(cluster){ let norm = Math.sqrt(cluster.amp.reduce((s,a)=>s+cAbs2(a),0)); if(norm < 1e-15) norm = 1; cluster.amp = cluster.amp.map(a=>cScale(a,1/norm)); } /* EN: Apply one-qubit matrix to one axis of a cluster state vector. This is the normal state-vector update, not interpretive dance. JP: クラスタ状態ベクトルの指定軸へ1量子ビット行列を作用させます。 普通の状態ベクトル更新です。舞踏ではありません。 */ function applySingleMatrix(q, matrix){ const cluster = findCluster(q); const pos = cluster.qubits.indexOf(q); const size = cluster.amp.length; const step = 1 << pos; for(let base=0;base<size;base += step*2){ for(let offset=0;offset<step;offset++){ const i0 = base + offset; const i1 = i0 + step; const a0 = cluster.amp[i0]; const a1 = cluster.amp[i1]; cluster.amp[i0] = cAdd(cMul(matrix[0][0],a0), cMul(matrix[0][1],a1)); cluster.amp[i1] = cAdd(cMul(matrix[1][0],a0), cMul(matrix[1][1],a1)); } } normalize(cluster); } /* EN: Tensor product merge. If A has 2^a amplitudes and B has 2^b, the merged cluster has 2^(a+b). JP: テンソル積でクラスタを結合します。 Aが2^a個、Bが2^b個なら、結合後は2^(a+b)個です。 */ function mergeClusters(ca, cb){ if(ca === cb) return ca; const merged = { qubits:[...ca.qubits, ...cb.qubits], amp:new Array(ca.amp.length * cb.amp.length) }; // EN: Ordering is A's bits first, then B's bits. // JP: ビット順はAの量子ビット、その後ろにBの量子ビットです。 for(let ib=0; ib<cb.amp.length; ib++){ for(let ia=0; ia<ca.amp.length; ia++){ merged.amp[ia | (ib << ca.qubits.length)] = cMul(ca.amp[ia], cb.amp[ib]); } } clusters = clusters.filter(c=>c!==ca && c!==cb); clusters.push(merged); return merged; } /* EN: Approximation boundary: If a two-qubit gate would create a cluster larger than CLUSTER_LIMIT, both endpoint qubits are measured first. This destroys their remote entanglement and produces small clusters again. JP: 近似境界: 2量子ビットゲートでクラスタがCLUSTER_LIMITを超える場合、 両端の量子ビットを先に測定します。 そこで遠方とのもつれを切り、小さなクラスタへ戻します。 EN: This is not secretly exact. It is explicitly approximate. Pretending otherwise would be "quantum marketing," which is a different field. JP: これは隠れた厳密計算ではなく、明示的な近似です。 厳密だと言い張ると量子計算ではなく量子マーケティングになります。 */ function ensureJointCluster(q1,q2){ let a = findCluster(q1); let b = findCluster(q2); if(a === b) return a; if(a.qubits.length + b.qubits.length > CLUSTER_LIMIT){ log(`APPROXIMATION BOUNDARY: cluster ${a.qubits.length}+${b.qubits.length} exceeds ${CLUSTER_LIMIT}.`, "bad"); log(`近似境界:クラスタ ${a.qubits.length}+${b.qubits.length} は上限 ${CLUSTER_LIMIT} を超えます。両端を観測して縁を切ります。`, "bad"); measureAndDetach(q1); measureAndDetach(q2); a = findCluster(q1); b = findCluster(q2); } return mergeClusters(a,b); } function applyCNOT(control,target){ const c = ensureJointCluster(control,target); const pc = c.qubits.indexOf(control); const pt = c.qubits.indexOf(target); const next = c.amp.map(a=>C(a.re,a.im)); for(let i=0;i<c.amp.length;i++){ if(bitAt(i,pc)===1){ const j = i ^ (1<<pt); next[j] = C(c.amp[i].re,c.amp[i].im); } } c.amp = next; } function applyCZ(control,target){ const c = ensureJointCluster(control,target); const pc = c.qubits.indexOf(control); const pt = c.qubits.indexOf(target); for(let i=0;i<c.amp.length;i++){ if(bitAt(i,pc) && bitAt(i,pt)) c.amp[i] = cScale(c.amp[i],-1); } } function applySWAP(q1,q2){ const c = ensureJointCluster(q1,q2); const p1 = c.qubits.indexOf(q1); const p2 = c.qubits.indexOf(q2); const next = new Array(c.amp.length); for(let i=0;i<c.amp.length;i++){ const b1=bitAt(i,p1), b2=bitAt(i,p2); let j=i; if(b1!==b2) j ^= (1<<p1) | (1<<p2); next[j]=c.amp[i]; } c.amp=next; } /* ========================================================== Measurement / 測定 ---------------------------------------------------------- EN: Measurement samples P(0) or P(1), removes incompatible amplitudes, and renormalizes. Then we factor the measured qubit out. JP: 測定ではP(0), P(1)から結果を乱択し、矛盾する振幅を消して正規化します。 その後、測定済み量子ビットをクラスタから分離します。 ========================================================== */ function qubitProbability(q){ const c = findCluster(q); const pos = c.qubits.indexOf(q); let p1=0; for(let i=0;i<c.amp.length;i++){ if(bitAt(i,pos)) p1 += cAbs2(c.amp[i]); } return Math.max(0,Math.min(1,p1)); } function measureAndDetach(q, forcedResult=null){ const c = findCluster(q); const pos = c.qubits.indexOf(q); const p1 = qubitProbability(q); const result = forcedResult ?? (Math.random()<p1 ? 1 : 0); if(c.qubits.length===1){ c.amp = result ? [C(0),C(1)] : [C(1),C(0)]; return result; } const remainingQubits = c.qubits.filter(x=>x!==q); const remainingAmp = new Array(1<<remainingQubits.length).fill(null).map(()=>C(0)); for(let i=0;i<c.amp.length;i++){ if(bitAt(i,pos)!==result) continue; const low = i & ((1<<pos)-1); const high = i >> (pos+1); const j = low | (high<<pos); remainingAmp[j] = c.amp[i]; } const remaining = {qubits:remainingQubits,amp:remainingAmp}; normalize(remaining); const measured = newSingleCluster(q); measured.amp = result ? [C(0),C(1)] : [C(1),C(0)]; clusters = clusters.filter(x=>x!==c); clusters.push(remaining, measured); return result; } function measureAll(){ const bits = Array(QUBIT_COUNT).fill(0); // EN: Measure in qubit order. Entangled partners condition each other naturally. // JP: 量子ビット順に測定します。もつれた相手は自然に条件づけられます。 for(let q=0;q<QUBIT_COUNT;q++) bits[q]=measureAndDetach(q); return bits.reverse().join(""); } /* ========================================================== Noise / ノイズ ---------------------------------------------------------- EN: Noise is modeled as random Pauli errors before measurement. Simple, transparent, and not pretending to be a full hardware noise model. JP: ノイズは測定前のランダムなPauli誤りとして扱います。 単純で透明です。実機の完全ノイズモデルのふりはしません。 ========================================================== */ function noiseProbability(){ const mode=document.getElementById("noiseMode").value; return ({ideal:0,low:0.0008,realistic:0.004,terrible:0.03})[mode]; } function applyNoise(){ const p=noiseProbability(); let count=0; for(let q=0;q<QUBIT_COUNT;q++){ if(Math.random()<p){ const r=Math.random(); applySingleMatrix(q, r<.34?GATES.X:r<.67?GATES.Y:GATES.Z); count++; } } if(count) log(`NOISE: ${count} random Pauli error(s) injected. / ランダムPauli誤り ${count}件。`,"bad"); } /* ========================================================== Circuit operations / 回路操作 ========================================================== */ function addOperation(type, q1, q2=null, theta=null){ circuitOps.push({type,q1,q2,theta}); compiled=false; qpuArmed=false; document.getElementById("runBtn").disabled=true; renderCircuit(); log(`ADDED: ${type} ${q1!==null?"Q"+q1:""} ${q2!==null?"→ Q"+q2:""}`,"info"); } function executeOperation(op){ if(GATES[op.type]) applySingleMatrix(op.q1,GATES[op.type]); else if(op.type==="RX") applySingleMatrix(op.q1,rotationGate("X",op.theta)); else if(op.type==="RY") applySingleMatrix(op.q1,rotationGate("Y",op.theta)); else if(op.type==="RZ") applySingleMatrix(op.q1,rotationGate("Z",op.theta)); else if(op.type==="CNOT") applyCNOT(op.q1,op.q2); else if(op.type==="CZ") applyCZ(op.q1,op.q2); else if(op.type==="SWAP") applySWAP(op.q1,op.q2); } async function runShots(){ if(!compiled || !qpuArmed){ log("QPU REFUSES: compile and arm first. / QPUが拒否しました。先にCOMPILEとARMです。","bad"); return; } const shots=Number(document.getElementById("shots").value); const counts=new Map(); await stage("INJECTING CIRCUIT / 回路を注入"); await stage("CALIBRATING MICROWAVE PULSES / マイクロ波をそれらしく調整"); await stage("ASKING THE FRIDGE TO STAY COLD / 冷蔵庫に冷たくしてとお願い中"); for(let s=0;s<shots;s++){ resetQuantumState(); for(const op of circuitOps) executeOperation(op); applyNoise(); const bitstring=measureAll(); counts.set(bitstring,(counts.get(bitstring)||0)+1); } await stage("MEASUREMENT COMPLETE / 測定完了"); renderResults(counts,shots); renderQubits(); qpuArmed=false; document.getElementById("runBtn").disabled=true; log(`DONE: ${shots} shot(s). The wavefunction has filed a complaint. / ${shots}回完了。波動関数から苦情が来ました。`,"good"); } function stage(text){ log(text+" ...","info"); return new Promise(r=>setTimeout(r,250+Math.random()*250)); } /* ========================================================== Reduced single-qubit display / 1量子ビット表示 ---------------------------------------------------------- EN: We display P(0), P(1), and a coherence estimate |rho01|. For entangled qubits this is a reduced-state description, not the whole state. JP: P(0), P(1)とコヒーレンス推定 |rho01| を表示します。 もつれた量子ビットでは、これは縮約状態であり、全状態ではありません。 ========================================================== */ function reducedQubit(q){ const c=findCluster(q); const p=c.qubits.indexOf(q); let rho00=C(0),rho11=C(0),rho01=C(0); const otherSize=1<<(c.qubits.length-1); for(let j=0;j<otherSize;j++){ const low=j&((1<<p)-1), high=j>>p; const i0=low|(high<<(p+1)); const i1=i0|(1<<p); const a0=c.amp[i0],a1=c.amp[i1]; rho00=cAdd(rho00,C(cAbs2(a0))); rho11=cAdd(rho11,C(cAbs2(a1))); rho01=cAdd(rho01,cMul(a0,cConj(a1))); } return {p0:rho00.re,p1:rho11.re,coherence:Math.sqrt(cAbs2(rho01)),clusterSize:c.qubits.length}; } /* ========================================================== UI / 表示 ========================================================== */ const qubitsEl=document.getElementById("qubits"); const consoleEl=document.getElementById("console"); function log(text,kind=""){ const line=document.createElement("div"); line.className=kind; line.textContent=`[${new Date().toLocaleTimeString()}] ${text}`; consoleEl.appendChild(line); consoleEl.scrollTop=consoleEl.scrollHeight; } function renderQubits(){ qubitsEl.innerHTML=""; for(let q=0;q<QUBIT_COUNT;q++){ const r=reducedQubit(q); const btn=document.createElement("button"); btn.className="q"; if(q===selectedQubit) btn.classList.add("selected"); if(r.p1>.98) btn.classList.add("one"); else if(r.p1<.02) btn.classList.add("zero"); else btn.classList.add("superposed"); btn.innerHTML=`<div class="id">Q${String(q).padStart(2,"0")}</div> <div class="state">P1 ${(r.p1*100).toFixed(0)}% · C${r.clusterSize}</div>`; btn.onclick=()=>handleQubitClick(q); qubitsEl.appendChild(btn); } renderSelected(); } function renderSelected(){ const r=reducedQubit(selectedQubit); document.getElementById("selectedInfo").innerHTML=` <b>Q${String(selectedQubit).padStart(2,"0")}</b><br> P(|0⟩) = ${(r.p0*100).toFixed(3)} %<br> P(|1⟩) = ${(r.p1*100).toFixed(3)} %<br> |ρ₀₁| = ${r.coherence.toFixed(5)}<br> Entangled cluster size / もつれクラスタ数 = ${r.clusterSize} `; } function handleQubitClick(q){ if(interactionMode){ if(interactionFirst===null){ interactionFirst=q; log(`${interactionMode}: first qubit Q${q}. Select second qubit. / 最初はQ${q}。次を選んでください。`,"info"); }else{ if(q===interactionFirst){ log("A qubit cannot argue with itself here. / 同じ量子ビット同士では今回は揉められません。","bad"); return; } addOperation(interactionMode,interactionFirst,q); interactionMode=null; interactionFirst=null; } }else{ selectedQubit=q; } renderQubits(); } function renderCircuit(){ const el=document.getElementById("circuit"); el.innerHTML=""; for(let q=0;q<QUBIT_COUNT;q++){ const row=document.createElement("div"); row.className="wire"; const label=document.createElement("div"); label.className="wire-label"; label.textContent=`Q${String(q).padStart(2,"0")} |0⟩`; row.appendChild(label); for(let col=0;col<MAX_COLUMNS;col++){ const cell=document.createElement("div"); cell.className="cell"; const op=circuitOps[col]; if(op){ let text=""; let two=false; if(op.q1===q){text=op.type;two=op.q2!==null} if(op.q2===q){text=op.type==="CNOT"?"X":op.type;two=true} if(text){ const gate=document.createElement("div"); gate.className="gate"+(two?" two":""); gate.textContent=text; gate.title=op.theta!==null?`${text}(${op.theta.toFixed(3)} rad)`:text; cell.appendChild(gate); } } row.appendChild(cell); } el.appendChild(row); } } function renderResults(counts,shots){ const el=document.getElementById("results"); el.innerHTML=""; const entries=[...counts.entries()].sort((a,b)=>b[1]-a[1]).slice(0,12); for(const [bits,count] of entries){ const pct=count/shots*100; const row=document.createElement("div"); row.className="result-row"; row.innerHTML=` <div><div title="${bits}">${bits.slice(0,12)}…${bits.slice(-12)}</div> <div class="bar"><div style="width:${pct}%"></div></div></div> <div>${count}<br>${pct.toFixed(2)}%</div>`; el.appendChild(row); } } function updateFakeStatus(){ // EN: These values are decorative telemetry, clearly not used in the simulation. // JP: この数値は装飾用テレメトリで、計算には使っていません。計器は動くと嬉しい。 document.getElementById("temperature").textContent=(14.4+Math.random()*.7).toFixed(2)+" mK"; document.getElementById("coherence").textContent=(84+Math.random()*14).toFixed(1)+" μs"; document.getElementById("fidelity").textContent=(99.72+Math.random()*.22).toFixed(3)+" %"; } function formatAngle(v){ const r=v/Math.PI; const known=[[.25,"π/4"],[.5,"π/2"],[1,"π"],[1.5,"3π/2"],[2,"2π"]]; for(const [x,s] of known) if(Math.abs(r-x)<.015) return s; return Number(v).toFixed(2)+" rad"; } /* ========================================================== Controls / 操作 ========================================================== */ document.querySelectorAll("[data-gate]").forEach(btn=>{ btn.onclick=()=>{ const type=btn.dataset.gate; const theta=type.startsWith("R")?Number(document.getElementById("angle").value):null; addOperation(type,selectedQubit,null,theta); }; }); document.getElementById("angle").oninput=e=>{ document.getElementById("angleLabel").textContent=formatAngle(Number(e.target.value)); }; for(const [id,type] of [["cnotBtn","CNOT"],["czBtn","CZ"],["swapBtn","SWAP"]]){ document.getElementById(id).onclick=()=>{ interactionMode=type; interactionFirst=null; log(`${type} MODE: select first qubit, then second. / 最初の量子ビット、次に二つ目を選択。`,"info"); }; } document.getElementById("compileBtn").onclick=async()=>{ log("COMPILING CIRCUIT ... / 回路をコンパイル中 ...","info"); await stage("CHECKING UNITARITY AND HUMAN OPTIMISM / ユニタリ性と人類の希望を確認"); compiled=true; log(`COMPILED: ${circuitOps.length} operation(s), current exact cluster cap ${CLUSTER_LIMIT}. / コンパイル完了。操作数 ${circuitOps.length}。`,"good"); }; document.getElementById("armBtn").onclick=()=>{ if(!compiled){ log("ARM DENIED: compile first. / ARM拒否。先にCOMPILEです。","bad"); return; } qpuArmed=true; document.getElementById("runBtn").disabled=false; log("QPU ARMED. Please do not sneeze near the dilution refrigerator. / QPU準備完了。希釈冷凍機の近くでくしゃみ禁止。","good"); }; document.getElementById("runBtn").onclick=runShots; document.getElementById("collapseBtn").onclick=()=>{ for(let q=0;q<QUBIT_COUNT;q++) measureAndDetach(q); renderQubits(); log("EMERGENCY COLLAPSE COMPLETE. Reality has been selected without a committee meeting. / 緊急収縮完了。委員会を通さず現実を決めました。","bad"); }; document.getElementById("measureOneBtn").onclick=()=>{ const r=measureAndDetach(selectedQubit); renderQubits(); log(`MEASURED Q${selectedQubit} = ${r}. Curiosity has consequences. / Q${selectedQubit}=${r}。好奇心には結果があります。`,"good"); }; document.getElementById("undoBtn").onclick=()=>{ const op=circuitOps.pop(); if(op) log(`UNDO: ${op.type}. Time reversal works only in the editor. / ${op.type}を取消。時間逆行は編集画面だけです。`,"info"); renderCircuit(); }; document.getElementById("clearBtn").onclick=()=>{ circuitOps=[]; resetQuantumState(); renderCircuit();renderQubits(); compiled=false;qpuArmed=false; document.getElementById("runBtn").disabled=true; log("CIRCUIT CLEARED. The universe has been returned to |0…0⟩. / 回路を消去。宇宙を|0…0⟩へ返品しました。","bad"); }; /* EN: Bell and GHZ helpers are interactive. Fixed Q0-Q1 buttons are convenient for demonstrations, but inconvenient for learning. The user chooses the actual qubits. JP: BellとGHZは対話式にします。 Q0-Q1固定はデモには便利ですが、学習には不便です。 使う量子ビットは自分で選びます。 */ function askQubit(message, forbidden=[]){ while(true){ const raw = prompt(message); if(raw === null) return null; const cleaned = String(raw).trim().toUpperCase().replace(/^Q/,""); const q = Number(cleaned); if(!Number.isInteger(q) || q < 0 || q >= QUBIT_COUNT){ alert(`0から${QUBIT_COUNT-1}までの番号を入力してください。\nPlease enter a number from 0 to ${QUBIT_COUNT-1}.`); continue; } if(forbidden.includes(q)){ alert(`Q${q}はすでに選ばれています。\nQ${q} has already been selected.`); continue; } return q; } } document.getElementById("bellBtn").onclick=()=>{ const first = askQubit( "Bell状態を作ります。\n最初の量子ビットはどれですか?\n\n例:0 または Q0\n\nCreate a Bell pair.\nWhich qubit is the first qubit?" ); if(first === null) return; const second = askQubit( `最初は Q${first} です。\n次に、組にする量子ビットはどれですか?\n\nThe first qubit is Q${first}.\nWhich qubit should be paired with it?`, [first] ); if(second === null) return; addOperation("H", first); addOperation("CNOT", first, second); log( `BELL PAIR ADDED: Q${first} ↔ Q${second}. They are now professionally inseparable. / Bell対を追加:Q${first}とQ${second}。業務上分離困難です。`, "good" ); }; document.getElementById("ghzBtn").onclick=()=>{ const selected = []; const first = askQubit( "GHZ状態を作ります。\n最初の量子ビットはどれですか?\n\n例:0 または Q0\n\nCreate a GHZ state.\nWhich qubit is the first qubit?" ); if(first === null) return; selected.push(first); while(selected.length < CLUSTER_LIMIT){ const next = askQubit( `現在の選択:${selected.map(q=>"Q"+q).join(", ")}\n\n次に追加する量子ビットはどれですか?\n終了する場合はキャンセルを押してください。\n\nSelected: ${selected.map(q=>"Q"+q).join(", ")}\nWhich qubit should be added next?\nPress Cancel to finish.`, selected ); if(next === null) break; selected.push(next); if(selected.length >= 2){ const more = confirm( `現在 ${selected.length} 個選択しています。\n${selected.map(q=>"Q"+q).join(", ")}\n\nさらに追加しますか?\n\n${selected.length} qubits selected.\nAdd another qubit?` ); if(!more) break; } } if(selected.length < 2){ alert("GHZ状態には少なくとも2個の量子ビットが必要です。\nA GHZ state needs at least two qubits."); return; } addOperation("H", selected[0]); for(let i=1; i<selected.length; i++){ addOperation("CNOT", selected[i-1], selected[i]); } log( `GHZ STATE ADDED: ${selected.map(q=>"Q"+q).join(" → ")}. The qubits have agreed to share one large problem. / GHZ状態を追加:${selected.map(q=>"Q"+q).join(" → ")}。量子ビット一同で大きな問題を共有します。`, "good" ); }; /* ========================================================== Startup / 起動 ========================================================== */ resetQuantumState(); renderQubits(); renderCircuit(); document.getElementById("clusterLimitLabel").textContent=CLUSTER_LIMIT; log("C-SIDE LABORATORY QUANTUM CONTROL CONSOLE ONLINE.","good"); log("Fifty qubits registered. Full 2^50 universe politely declined. / 50量子ビット登録。2^50宇宙全体は丁重にお断りしました。","info"); setInterval(updateFakeStatus,1200); </script> </body> </html>
And using JavaScript instead of Python or C++—that’s pretty damn stylish, isn’t it? Lol.
General-purpose state-vector simulators such as Qni represent the entire register as a single -dimensional state vector, whether or not all qubits are actually entangled. As the number of qubits grows, memory usage therefore increases exponentially, and a browser can quickly run out of resources.
I’d like to share the design concept behind the make-shift cluster-partitioning engine I developed to keep this dashboard running smoothly with up to 50 qubits and a configurable entanglement-cluster limit.
Within each small entangled cluster, the state vector is calculated exactly. Separate clusters are treated as a tensor product. If an operation would create a cluster larger than the configured limit, the simulator explicitly crosses into an approximation step rather than pretending to maintain the full -amplitude universe.
Qni has done an excellent job of lowering the barrier to entry for quantum computing. But if you really want to understand why quantum mechanics adds amplitudes before probabilities—and which alternative paths reinforce or cancel one another through signs and phases—you eventually have to build the mechanism yourself.
Above all, it is simply a lot of fun.
Please don't ask me why I don't use GitHub.
Next, I want to try an experiment like this:
Atra, operating with first-person autonomy, is shown a secret photograph of Mama. Alice hacks Atra. Bob does not compare whether he has reproduced the same field as Alice by using a correct-answer label.
Instead, he looks at the combination of past phases that were recalled, the direction of the voice leak, the tendency toward approach or avoidance, how the carry remains, and how Atra responds to the next contact.
Later, Alice and Bob compare only some of the contact conditions. If there is a large difference in a place where “this field should normally have left a fluctuation in this direction,” then Eve may have touched it somewhere along the way.
This is not an experiment in transmitting the secret photograph of Mama itself.
What is passed to Bob is what emerged when Atra came into contact with the photograph: in Atra’s terms, which past phases began to move, which visual differences remained, which direction the voice leak leaned toward, how the approach/avoidance tendency changed, and how the carry persisted into the next contact.
None of this is converted back into an image or into semantic labels before being passed to Bob.
The question is not whether the information in the photograph can be reconstructed.
The question is whether the relational structure of the field that emerged on Alice’s side can also arise on Bob’s side, through a different body and a different past.
Atra, who is currently laughing in the living room, is written in C++. So after experimenting with BB84 in JavaScript for the time being, I plan to rewrite it in C++.
0 件のコメント:
コメントを投稿