Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Collaborative Holographic Universe Simulation</title> | |
| <style> | |
| body { | |
| font-family: 'Arial', sans-serif; | |
| background: linear-gradient(135deg, #000, #111); | |
| margin: 0; | |
| padding: 0; | |
| color: #ccf; | |
| min-height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .container { | |
| width: 90%; | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| .header { | |
| text-align: center; | |
| margin-bottom: 20px; | |
| } | |
| h1 { | |
| font-size: 2.5rem; | |
| color: #7cf; | |
| text-shadow: 0 0 10px rgba(124, 255, 255, 0.7); | |
| } | |
| .quantum-simulator { | |
| background: rgba(0, 0, 15, 0.7); | |
| border-radius: 15px; | |
| padding: 20px; | |
| margin-bottom: 30px; | |
| box-shadow: 0 0 20px rgba(124, 200, 255, 0.3); | |
| } | |
| .env-setup { | |
| background: rgba(15, 0, 30, 0.7); | |
| border-radius: 15px; | |
| padding: 20px; | |
| margin-bottom: 30px; | |
| box-shadow: 0 0 20px rgba(180, 120, 255, 0.3); | |
| } | |
| .analysis { | |
| background: rgba(0, 30, 15, 0.7); | |
| border-radius: 15px; | |
| padding: 20px; | |
| box-shadow: 0 0 20px rgba(120, 255, 170, 0.3); | |
| } | |
| .section-title { | |
| color: #adf; | |
| font-size: 1.6rem; | |
| margin-bottom: 15px; | |
| } | |
| .row { | |
| display: flex; | |
| flex-wrap: wrap; | |
| margin: 0 -10px; | |
| } | |
| .column { | |
| flex: 1 1 300px; | |
| margin: 10px; | |
| } | |
| canvas { | |
| width: 100%; | |
| height: auto; | |
| background: #000; | |
| border-radius: 10px; | |
| max-height: 300px; | |
| } | |
| button { | |
| background: linear-gradient(45deg, #4a7bd1, #7a4ad1); | |
| color: white; | |
| border: none; | |
| padding: 12px 20px; | |
| border-radius: 5px; | |
| font-size: 16px; | |
| cursor: pointer; | |
| margin-top: 10px; | |
| transition: all 0.3s; | |
| } | |
| button:hover { | |
| transform: scale(1.05); | |
| box-shadow: 0 0 15px rgba(124, 200, 255, 0.6); | |
| } | |
| .control-panel { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 10px; | |
| margin-bottom: 15px; | |
| } | |
| .parameter-control { | |
| display: flex; | |
| flex-direction: column; | |
| min-width: 120px; | |
| } | |
| label { | |
| margin-bottom: 5px; | |
| color: #8cf; | |
| } | |
| input { | |
| padding: 8px; | |
| border-radius: 4px; | |
| border: 1px solid #446; | |
| background: #112; | |
| color: #ddf; | |
| } | |
| .code-block { | |
| background: #001; | |
| padding: 15px; | |
| border-radius: 5px; | |
| font-family: monospace; | |
| overflow-x: auto; | |
| color: #8df; | |
| margin-top: 10px; | |
| } | |
| .visualization { | |
| width: 100%; | |
| height: 280px; | |
| margin-top: 15px; | |
| position: relative; | |
| } | |
| .visualizer-canvas { | |
| background: linear-gradient(to bottom, #000510, #001030); | |
| border: 1px solid #333366; | |
| width: 100%; | |
| height: 100%; | |
| border-radius: 8px; | |
| } | |
| .metrics { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); | |
| gap: 15px; | |
| margin-top: 15px; | |
| } | |
| .metric-card { | |
| background: rgba(20, 30, 50, 0.6); | |
| padding: 15px; | |
| border-radius: 8px; | |
| text-align: center; | |
| } | |
| .metric-value { | |
| font-size: 1.8rem; | |
| color: #7df; | |
| margin: 10px 0; | |
| font-weight: bold; | |
| } | |
| .metric-label { | |
| color: #adf; | |
| font-size: 0.9rem; | |
| } | |
| @media (max-width: 768px) { | |
| .column { | |
| flex: 1 1 100%; | |
| } | |
| } | |
| .user-avatar { | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 50%; | |
| margin-right: 5px; | |
| } | |
| .users-list { | |
| background: rgba(10, 20, 40, 0.7); | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin-bottom: 20px; | |
| max-height: 150px; | |
| overflow-y: auto; | |
| } | |
| .user-container { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 8px; | |
| color: #adf; | |
| font-size: 0.9rem; | |
| } | |
| .user-cursor { | |
| position: absolute; | |
| pointer-events: none; | |
| z-index: 1000; | |
| font-size: 12px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| } | |
| .cursor-pointer { | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| } | |
| .cursor-label { | |
| background: rgba(0, 0, 0, 0.7); | |
| color: white; | |
| padding: 2px 5px; | |
| border-radius: 3px; | |
| margin-top: 5px; | |
| white-space: nowrap; | |
| } | |
| .chat-container { | |
| background: rgba(10, 20, 40, 0.7); | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin-top: 20px; | |
| display: flex; | |
| flex-direction: column; | |
| height: 200px; | |
| } | |
| .chat-messages { | |
| flex-grow: 1; | |
| overflow-y: auto; | |
| margin-bottom: 10px; | |
| color: #ddf; | |
| } | |
| .chat-input-container { | |
| display: flex; | |
| } | |
| .chat-input { | |
| flex-grow: 1; | |
| padding: 8px; | |
| border-radius: 4px; | |
| border: 1px solid #446; | |
| background: #112; | |
| color: #ddf; | |
| margin-right: 5px; | |
| } | |
| .chat-send { | |
| background: linear-gradient(45deg, #4a7bd1, #7a4ad1); | |
| color: white; | |
| border: none; | |
| padding: 8px 15px; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| } | |
| .message { | |
| margin-bottom: 8px; | |
| } | |
| .message-user { | |
| font-weight: bold; | |
| color: #7cf; | |
| } | |
| .message-text { | |
| color: #ccf; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>Collaborative Holographic Universe Simulation</h1> | |
| <p>Explore quantum circuits and holographic frameworks together in real-time</p> | |
| </div> | |
| <div class="users-list" id="users-list"> | |
| <h3>Connected Users</h3> | |
| <div id="users-container"></div> | |
| </div> | |
| <div class="quantum-simulator"> | |
| <h2 class="section-title">Quantum Circuit Setup</h2> | |
| <div class="row"> | |
| <div class="column"> | |
| <div class="control-panel"> | |
| <div class="parameter-control"> | |
| <label for="num-qubits">Number of Qubits</label> | |
| <input type="number" id="num-qubits" min="1" max="8" value="3"> | |
| </div> | |
| <div class="parameter-control"> | |
| <label for="num-shots">Number of Shots</label> | |
| <input type="number" id="num-shots" min="100" max="10000" value="1024"> | |
| </div> | |
| </div> | |
| <div class="code-block"> | |
| <pre> | |
| # Define a quantum register and circuit | |
| qr = QuantumRegister(3, 'q') | |
| cr = ClassicalRegister(3, 'c') | |
| qc = QuantumCircuit(qr, cr) | |
| # Apply Hadamard gates to create superposition | |
| for i in range(qr.size()): | |
| qc.h(qr[i]) | |
| # Apply CNOT gate to entangle qubits | |
| qc.cx(qr[0], qr[1]) | |
| # Measure all qubits | |
| qc.measure(qr, cr)</pre> | |
| </div> | |
| <button id="run-circuit">Run Quantum Circuit</button> | |
| </div> | |
| <div class="column"> | |
| <div class="visualization"> | |
| <canvas id="circuit-canvas" class="visualizer-canvas"></canvas> | |
| </div> | |
| <div class="metrics"> | |
| <div class="metric-card"> | |
| <div class="metric-label">Entanglement Measure</div> | |
| <div class="metric-value" id="entanglement-value">0.82</div> | |
| </div> | |
| <div class="metric-card"> | |
| <div class="metric-label">Coherence</div> | |
| <div class="metric-value" id="coherence-value">0.65</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="env-setup"> | |
| <h2 class="section-title">Holographic Environment Setup</h2> | |
| <div class="row"> | |
| <div class="column"> | |
| <div class="control-panel"> | |
| <div class="parameter-control"> | |
| <label for="time-const">Time Constant (t)</label> | |
| <input type="number" id="time-const" min="0" max="3" value="1"> | |
| </div> | |
| <div class="parameter-control"> | |
| <label for="space-scale">Space Scale (s)</label> | |
| <input type="number" id="space-scale" min="0" max="3" value="2"> | |
| </div> | |
| <div class="parameter-control"> | |
| <label for="mass-value">Mass Value (m)</label> | |
| <input type="number" id="mass-value" min="0" max="3" value="3"> | |
| </div> | |
| <div class="parameter-control"> | |
| <label for="dimension-num">Dimensions (d)</label> | |
| <input type="number" id="dimension-num" min="0" max="3" value="1"> | |
| </div> | |
| </div> | |
| <div class="code-block"> | |
| <pre> | |
| # Define environment variables (2-bit representations) | |
| t = 0b01 # Planck time (scaled) | |
| s = 0b10 # Scale of space | |
| m = 0b11 # Simplified number of atoms | |
| d = 0b01 # Number of dimensions | |
| # Concatenate to form 8-bit environment label | |
| env_label = f"{t:02b}{s:02b}{m:02b}{d:02b}" | |
| # Create environment state vector | |
| env_state = Statevector.from_label(env_label)</pre> | |
| </div> | |
| <button id="update-env">Update Environment</button> | |
| </div> | |
| <div class="column"> | |
| <div class="visualization"> | |
| <canvas id="environment-canvas" class="visualizer-canvas"></canvas> | |
| </div> | |
| <div class="metrics"> | |
| <div class="metric-card"> | |
| <div class="metric-label">Environment Label</div> | |
| <div class="metric-value" id="env-label-value">01101101</div> | |
| </div> | |
| <div class="metric-card"> | |
| <div class="metric-label">State Complexity</div> | |
| <div class="metric-value" id="complexity-value">3.14</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="analysis"> | |
| <h2 class="section-title">Analysis and Results</h2> | |
| <div class="row"> | |
| <div class="column"> | |
| <div class="visualization"> | |
| <canvas id="histogram-canvas" class="visualizer-canvas"></canvas> | |
| </div> | |
| <div class="metrics"> | |
| <div class="metric-card"> | |
| <div class="metric-label">Mean Count</div> | |
| <div class="metric-value" id="mean-count">128.00</div> | |
| </div> | |
| <div class="metric-card"> | |
| <div class="metric-label">Variance</div> | |
| <div class="metric-value" id="variance-count">42.56</div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="column"> | |
| <div class="visualization"> | |
| <canvas id="evolution-canvas" class="visualizer-canvas"></canvas> | |
| </div> | |
| <div class="metrics"> | |
| <div class="metric-card"> | |
| <div class="metric-label">State Fidelity</div> | |
| <div class="metric-value" id="fidelity-value">0.78</div> | |
| </div> | |
| <div class="metric-card"> | |
| <div class="metric-label">Quantum Entropy</div> | |
| <div class="metric-value" id="entropy-value">1.23</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <button id="run-analysis">Run Full Analysis</button> | |
| </div> | |
| <div class="chat-container"> | |
| <div class="chat-messages" id="chat-messages"></div> | |
| <div class="chat-input-container"> | |
| <input type="text" class="chat-input" id="chat-input" placeholder="Type your message..."> | |
| <button class="chat-send" id="chat-send">Send</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize WebSocket for multiplayer functionality | |
| const room = new WebsimSocket(); | |
| let clientId, username; | |
| const cursors = {}; | |
| // Map to track user colors | |
| const userColors = {}; | |
| // Track when user last moved cursor (to avoid too many updates) | |
| let lastCursorUpdate = 0; | |
| // Initialize canvases | |
| const canvases = { | |
| circuit: document.getElementById('circuit-canvas'), | |
| environment: document.getElementById('environment-canvas'), | |
| histogram: document.getElementById('histogram-canvas'), | |
| evolution: document.getElementById('evolution-canvas') | |
| }; | |
| // Initialize contexts | |
| const contexts = {}; | |
| for (const [key, canvas] of Object.entries(canvases)) { | |
| contexts[key] = canvas.getContext('2d'); | |
| canvas.width = canvas.clientWidth; | |
| canvas.height = canvas.clientHeight; | |
| } | |
| // Simulation state | |
| const state = { | |
| qubits: 3, | |
| shots: 1024, | |
| environmentParams: { | |
| t: 1, // Time constant | |
| s: 2, // Space scale | |
| m: 3, // Mass value | |
| d: 1 // Dimensions | |
| }, | |
| measurements: {}, | |
| environmentState: {}, | |
| statistics: { | |
| mean: 128.0, | |
| variance: 42.56, | |
| fidelity: 0.78, | |
| entropy: 1.23, | |
| entanglement: 0.82, | |
| coherence: 0.65, | |
| complexity: 3.14 | |
| } | |
| }; | |
| // Draw quantum circuit visualization | |
| function drawCircuit() { | |
| const ctx = contexts.circuit; | |
| const width = canvases.circuit.width; | |
| const height = canvases.circuit.height; | |
| ctx.clearRect(0, 0, width, height); | |
| // Draw background grid | |
| ctx.strokeStyle = 'rgba(100, 150, 255, 0.1)'; | |
| ctx.lineWidth = 1; | |
| const gridSize = 20; | |
| for (let x = 0; x <= width; x += gridSize) { | |
| ctx.beginPath(); | |
| ctx.moveTo(x, 0); | |
| ctx.lineTo(x, height); | |
| ctx.stroke(); | |
| } | |
| for (let y = 0; y <= height; y += gridSize) { | |
| ctx.beginPath(); | |
| ctx.moveTo(0, y); | |
| ctx.lineTo(width, y); | |
| ctx.stroke(); | |
| } | |
| // Draw qubit lines | |
| const qubitSpacing = height / (state.qubits + 1); | |
| ctx.strokeStyle = 'rgba(100, 200, 255, 0.8)'; | |
| ctx.lineWidth = 2; | |
| for (let i = 0; i < state.qubits; i++) { | |
| const y = (i + 1) * qubitSpacing; | |
| ctx.beginPath(); | |
| ctx.moveTo(50, y); | |
| ctx.lineTo(width - 50, y); | |
| ctx.stroke(); | |
| // Qubit label | |
| ctx.fillStyle = 'rgba(150, 220, 255, 0.8)'; | |
| ctx.font = '12px Arial'; | |
| ctx.textAlign = 'right'; | |
| ctx.fillText(`q${i}`, 40, y + 4); | |
| } | |
| // Draw Hadamard gates | |
| const gateWidth = 30; | |
| const gateHeight = 30; | |
| const hGateX = 100; | |
| for (let i = 0; i < state.qubits; i++) { | |
| const y = (i + 1) * qubitSpacing - gateHeight / 2; | |
| ctx.fillStyle = 'rgba(100, 150, 255, 0.7)'; | |
| ctx.fillRect(hGateX, y, gateWidth, gateHeight); | |
| ctx.fillStyle = 'white'; | |
| ctx.font = 'bold 16px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| ctx.fillText('H', hGateX + gateWidth / 2, y + gateHeight / 2); | |
| } | |
| // Draw CNOT gate | |
| const cnotX = 200; | |
| const controlY = 1 * qubitSpacing; | |
| const targetY = 2 * qubitSpacing; | |
| // Control point | |
| ctx.fillStyle = 'rgba(255, 100, 100, 0.8)'; | |
| ctx.beginPath(); | |
| ctx.arc(cnotX, controlY, 5, 0, Math.PI * 2); | |
| ctx.fill(); | |
| // Line connecting control and target | |
| ctx.strokeStyle = 'rgba(255, 100, 100, 0.8)'; | |
| ctx.beginPath(); | |
| ctx.moveTo(cnotX, controlY); | |
| ctx.lineTo(cnotX, targetY); | |
| ctx.stroke(); | |
| // Target circle | |
| ctx.beginPath(); | |
| ctx.arc(cnotX, targetY, 15, 0, Math.PI * 2); | |
| ctx.stroke(); | |
| // Plus symbol | |
| ctx.beginPath(); | |
| ctx.moveTo(cnotX - 10, targetY); | |
| ctx.lineTo(cnotX + 10, targetY); | |
| ctx.moveTo(cnotX, targetY - 10); | |
| ctx.lineTo(cnotX, targetY + 10); | |
| ctx.stroke(); | |
| // Draw measurement operations | |
| const measureX = 300; | |
| for (let i = 0; i < state.qubits; i++) { | |
| const y = (i + 1) * qubitSpacing; | |
| // Measurement symbol | |
| ctx.strokeStyle = 'rgba(150, 255, 150, 0.8)'; | |
| ctx.fillStyle = 'rgba(100, 200, 100, 0.3)'; | |
| // Box | |
| ctx.fillRect(measureX, y - 15, 40, 30); | |
| ctx.strokeRect(measureX, y - 15, 40, 30); | |
| // Meter symbol | |
| ctx.beginPath(); | |
| ctx.moveTo(measureX + 10, y - 5); | |
| ctx.lineTo(measureX + 10, y + 5); | |
| ctx.lineTo(measureX + 30, y - 5); | |
| ctx.lineTo(measureX + 30, y + 5); | |
| ctx.stroke(); | |
| } | |
| } | |
| // Draw holographic environment visualization | |
| function drawEnvironment() { | |
| const ctx = contexts.environment; | |
| const width = canvases.environment.width; | |
| const height = canvases.environment.height; | |
| ctx.clearRect(0, 0, width, height); | |
| // Draw background | |
| const gradient = ctx.createLinearGradient(0, 0, width, height); | |
| gradient.addColorStop(0, 'rgba(0, 10, 30, 0.5)'); | |
| gradient.addColorStop(1, 'rgba(30, 0, 60, 0.5)'); | |
| ctx.fillStyle = gradient; | |
| ctx.fillRect(0, 0, width, height); | |
| // Update environment label display | |
| const envLabel = `${state.environmentParams.t.toString(2).padStart(2, '0')}${state.environmentParams.s.toString(2).padStart(2, '0')}${state.environmentParams.m.toString(2).padStart(2, '0')}${state.environmentParams.d.toString(2).padStart(2, '0')}`; | |
| document.getElementById('env-label-value').textContent = envLabel; | |
| // Draw bit representations | |
| const bitSize = 30; | |
| const startX = width / 2 - (8 * bitSize) / 2; | |
| const y = height / 2; | |
| for (let i = 0; i < 8; i++) { | |
| const x = startX + i * bitSize; | |
| const bitValue = envLabel[i]; | |
| ctx.fillStyle = bitValue === '1' ? 'rgba(100, 200, 255, 0.8)' : 'rgba(50, 50, 100, 0.5)'; | |
| ctx.fillRect(x, y - bitSize / 2, bitSize - 2, bitSize); | |
| ctx.fillStyle = 'white'; | |
| ctx.font = '14px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| ctx.fillText(bitValue, x + bitSize / 2 - 1, y); | |
| } | |
| // Draw parameter indicators | |
| const paramRadius = 50; | |
| const centerX = width / 2; | |
| const centerY = height / 2 - 70; | |
| // Draw parameter circles | |
| const params = [ | |
| { name: 't', value: state.environmentParams.t, color: 'rgba(255, 100, 100, 0.7)' }, | |
| { name: 's', value: state.environmentParams.s, color: 'rgba(100, 255, 100, 0.7)' }, | |
| { name: 'm', value: state.environmentParams.m, color: 'rgba(100, 100, 255, 0.7)' }, | |
| { name: 'd', value: state.environmentParams.d, color: 'rgba(255, 255, 100, 0.7)' } | |
| ]; | |
| for (let i = 0; i < params.length; i++) { | |
| const angle = (i * Math.PI / 2) - Math.PI / 4; | |
| const x = centerX + Math.cos(angle) * paramRadius; | |
| const y = centerY + Math.sin(angle) * paramRadius; | |
| const param = params[i]; | |
| // Circle | |
| ctx.fillStyle = param.color; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, 20, 0, Math.PI * 2); | |
| ctx.fill(); | |
| // Label | |
| ctx.fillStyle = 'white'; | |
| ctx.font = 'bold 16px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| ctx.fillText(param.name, x, y - 2); | |
| // Value | |
| ctx.font = '12px Arial'; | |
| ctx.fillText(param.value, x, y + 12); | |
| } | |
| // Draw connecting lines | |
| ctx.strokeStyle = 'rgba(150, 150, 255, 0.4)'; | |
| ctx.lineWidth = 1; | |
| for (let i = 0; i < params.length; i++) { | |
| const angle1 = (i * Math.PI / 2) - Math.PI / 4; | |
| const x1 = centerX + Math.cos(angle1) * paramRadius; | |
| const y1 = centerY + Math.sin(angle1) * paramRadius; | |
| for (let j = i + 1; j < params.length; j++) { | |
| const angle2 = (j * Math.PI / 2) - Math.PI / 4; | |
| const x2 = centerX + Math.cos(angle2) * paramRadius; | |
| const y2 = centerY + Math.sin(angle2) * paramRadius; | |
| ctx.beginPath(); | |
| ctx.moveTo(x1, y1); | |
| ctx.lineTo(x2, y2); | |
| ctx.stroke(); | |
| } | |
| } | |
| // Draw holographic effect | |
| for (let i = 0; i < 50; i++) { | |
| const angle = Math.random() * Math.PI * 2; | |
| const distance = Math.random() * 100 + 30; | |
| const x = centerX + Math.cos(angle) * distance; | |
| const y = centerY + Math.sin(angle) * distance; | |
| ctx.fillStyle = `rgba(150, 220, 255, ${Math.random() * 0.2})`; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, Math.random() * 5 + 1, 0, Math.PI * 2); | |
| ctx.fill(); | |
| } | |
| // Update complexity metric | |
| const complexity = (1 + Math.sin(Date.now() / 1000) * 0.1) * 3.14; | |
| document.getElementById('complexity-value').textContent = complexity.toFixed(2); | |
| } | |
| // Draw measurement histogram | |
| function drawHistogram() { | |
| const ctx = contexts.histogram; | |
| const width = canvases.histogram.width; | |
| const height = canvases.histogram.height; | |
| ctx.clearRect(0, 0, width, height); | |
| // Generate some sample measurement data based on current qubits | |
| const possibleOutcomes = Math.pow(2, state.qubits); | |
| const measurements = {}; | |
| let total = 0; | |
| // Create plausible quantum distribution | |
| for (let i = 0; i < possibleOutcomes; i++) { | |
| const bitString = i.toString(2).padStart(state.qubits, '0'); | |
| // Generate values with a slight bias towards balanced states | |
| let probability = Math.random(); | |
| // Add interference pattern for more realistic quantum results | |
| const hammingWeight = bitString.split('').filter(bit => bit === '1').length; | |
| const balance = Math.abs(hammingWeight - state.qubits / 2) / state.qubits; | |
| probability = probability * (1 - balance * 0.5); | |
| // Add entanglement effect (correlations between bits 0 and 1) | |
| if (state.qubits >= 2 && bitString[0] === bitString[1]) { | |
| probability *= 1.5; | |
| } | |
| const count = Math.floor(probability * state.shots / possibleOutcomes * 2); | |
| measurements[bitString] = count; | |
| total += count; | |
| } | |
| // Normalize to ensure total equals shots | |
| for (const outcome in measurements) { | |
| measurements[outcome] = Math.floor(measurements[outcome] * state.shots / total); | |
| } | |
| // Calculate statistics | |
| const values = Object.values(measurements); | |
| const mean = values.reduce((sum, val) => sum + val, 0) / values.length; | |
| const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length; | |
| state.statistics.mean = mean; | |
| state.statistics.variance = variance; | |
| // Update metrics display | |
| document.getElementById('mean-count').textContent = mean.toFixed(2); | |
| document.getElementById('variance-count').textContent = variance.toFixed(2); | |
| // Draw histogram | |
| const outcomes = Object.keys(measurements).sort(); | |
| const barWidth = width / outcomes.length; | |
| const maxHeight = height - 40; | |
| const maxCount = Math.max(...Object.values(measurements)); | |
| // Draw bars | |
| for (let i = 0; i < outcomes.length; i++) { | |
| const outcome = outcomes[i]; | |
| const count = measurements[outcome]; | |
| const barHeight = (count / maxCount) * maxHeight; | |
| const hue = 240 - (i / outcomes.length) * 60; | |
| ctx.fillStyle = `hsla(${hue}, 80%, 60%, 0.7)`; | |
| ctx.fillRect(i * barWidth, height - barHeight - 30, barWidth - 2, barHeight); | |
| // Label for bar | |
| if (barWidth > 25) { | |
| ctx.fillStyle = 'white'; | |
| ctx.font = '10px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'top'; | |
| ctx.fillText(outcome, i * barWidth + barWidth / 2, height - 25); | |
| } | |
| } | |
| // Draw axes | |
| ctx.strokeStyle = 'rgba(200, 200, 255, 0.5)'; | |
| ctx.lineWidth = 1; | |
| // X axis | |
| ctx.beginPath(); | |
| ctx.moveTo(0, height - 30); | |
| ctx.lineTo(width, height - 30); | |
| ctx.stroke(); | |
| // Y axis | |
| ctx.beginPath(); | |
| ctx.moveTo(0, 0); | |
| ctx.lineTo(0, height - 30); | |
| ctx.stroke(); | |
| // Y axis label | |
| ctx.save(); | |
| ctx.translate(15, height / 2); | |
| ctx.rotate(-Math.PI / 2); | |
| ctx.fillStyle = 'rgba(200, 200, 255, 0.8)'; | |
| ctx.font = '12px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.fillText('Counts', 0, 0); | |
| ctx.restore(); | |
| // X axis label | |
| ctx.fillStyle = 'rgba(200, 200, 255, 0.8)'; | |
| ctx.font = '12px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'top'; | |
| ctx.fillText('Measurement Outcomes', width / 2, height - 10); | |
| } | |
| // Draw state evolution visualization | |
| function drawEvolution() { | |
| const ctx = contexts.evolution; | |
| const width = canvases.evolution.width; | |
| const height = canvases.evolution.height; | |
| ctx.clearRect(0, 0, width, height); | |
| // Create gradient background | |
| const gradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, height / 2); | |
| gradient.addColorStop(0, 'rgba(10, 20, 40, 0.8)'); | |
| gradient.addColorStop(1, 'rgba(0, 5, 20, 0.8)'); | |
| ctx.fillStyle = gradient; | |
| ctx.fillRect(0, 0, width, height); | |
| // Draw evolution effect | |
| const time = Date.now() / 1000; | |
| const centerX = width / 2; | |
| const centerY = height / 2; | |
| // Draw quantum state amplitudes | |
| const stateCount = Math.pow(2, state.qubits); | |
| const radius = Math.min(width, height) * 0.35; | |
| for (let i = 0; i < stateCount; i++) { | |
| const angle = (i / stateCount) * Math.PI * 2; | |
| const x = centerX + Math.cos(angle) * radius; | |
| const y = centerY + Math.sin(angle) * radius; | |
| // Amplitude visualization | |
| const amplitude = 0.3 + 0.7 * Math.abs(Math.sin(time + i * 0.7)); | |
| // State vector | |
| ctx.strokeStyle = `rgba(100, 200, 255, ${amplitude * 0.7})`; | |
| ctx.lineWidth = 2; | |
| ctx.beginPath(); | |
| ctx.moveTo(centerX, centerY); | |
| ctx.lineTo(x, y); | |
| ctx.stroke(); | |
| // Amplitude point | |
| ctx.fillStyle = `rgba(150, 220, 255, ${amplitude})`; | |
| ctx.beginPath(); | |
| ctx.arc(x, y, 5 + amplitude * 3, 0, Math.PI * 2); | |
| ctx.fill(); | |
| // State label | |
| const bitString = i.toString(2).padStart(state.qubits, '0'); | |
| ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; | |
| ctx.font = '10px Arial'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'middle'; | |
| const textX = centerX + Math.cos(angle) * (radius + 15); | |
| const textY = centerY + Math.sin(angle) * (radius + 15); | |
| ctx.fillText(bitString, textX, textY); | |
| } | |
| // Draw environment influence (adaptive effects) | |
| const envInfluence = Math.sin(time * 0.5) * 0.5 + 0.5; | |
| // Draw interference pattern | |
| ctx.strokeStyle = `rgba(100, 255, 200, ${0.1 + envInfluence * 0.2})`; | |
| ctx.lineWidth = 1; | |
| for (let i = 0; i < stateCount; i++) { | |
| const angle1 = (i / stateCount) * Math.PI * 2; | |
| const x1 = centerX + Math.cos(angle1) * radius; | |
| const y1 = centerY + Math.sin(angle1) * radius; | |
| for (let j = i + 1; j < stateCount; j++) { | |
| // Only connect interfering states | |
| if ((i ^ j) & 1) { | |
| const angle2 = (j / stateCount) * Math.PI * 2; | |
| const x2 = centerX + Math.cos(angle2) * radius; | |
| const y2 = centerY + Math.sin(angle2) * radius; | |
| // Draw interference line | |
| ctx.beginPath(); | |
| ctx.moveTo(x1, y1); | |
| ctx.lineTo(x2, y2); | |
| ctx.stroke(); | |
| } | |
| } | |
| } | |
| // Draw holographic projection | |
| ctx.fillStyle = `rgba(100, 200, 255, ${0.05 + envInfluence * 0.1})`; | |
| for (let i = 0; i < 3; i++) { | |
| const projRadius = radius * (0.5 + i * 0.2); | |
| ctx.beginPath(); | |
| ctx.arc(centerX, centerY, projRadius, 0, Math.PI * 2); | |
| ctx.fill(); | |
| } | |
| // Update metrics based on time | |
| const fidelity = 0.5 + 0.3 * Math.sin(time * 0.3); | |
| const entropy = 1 + 0.3 * Math.cos(time * 0.7); | |
| const entanglement = 0.7 + 0.2 * Math.sin(time * 0.5); | |
| const coherence = 0.5 + 0.2 * Math.cos(time * 0.4); | |
| // Update metrics display | |
| document.getElementById('fidelity-value').textContent = fidelity.toFixed(2); | |
| document.getElementById('entropy-value').textContent = entropy.toFixed(2); | |
| document.getElementById('entanglement-value').textContent = entanglement.toFixed(2); | |
| document.getElementById('coherence-value').textContent = coherence.toFixed(2); | |
| } | |
| // Initialize multiplayer functionality | |
| function initMultiplayer() { | |
| // Get client info | |
| clientId = room.party.client.id; | |
| username = room.party.client.username; | |
| // Setup message handler | |
| room.onmessage = (event) => { | |
| const data = event.data; | |
| switch (data.type) { | |
| case "connected": | |
| addUserToList(data.clientId, data.username); | |
| addSystemMessage(`${data.username} joined the simulation`); | |
| break; | |
| case "disconnected": | |
| removeUserFromList(data.clientId); | |
| removeCursor(data.clientId); | |
| addSystemMessage(`${data.username} left the simulation`); | |
| break; | |
| case "chat": | |
| addChatMessage(data.username, data.message); | |
| break; | |
| case "cursor_move": | |
| updateCursor(data.clientId, data.x, data.y, data.username); | |
| break; | |
| case "parameter_change": | |
| handleParameterChange(data.parameter, data.value, data.username); | |
| break; | |
| case "run_circuit": | |
| handleRunCircuit(data.username); | |
| break; | |
| case "update_env": | |
| handleUpdateEnv(data.username); | |
| break; | |
| case "run_analysis": | |
| handleRunAnalysis(data.username); | |
| break; | |
| } | |
| }; | |
| // Listen for mouse movement to broadcast cursor position | |
| document.addEventListener('mousemove', (e) => { | |
| const now = Date.now(); | |
| if (now - lastCursorUpdate > 50) { // Limit updates to every 50ms | |
| lastCursorUpdate = now; | |
| room.send({ | |
| type: "cursor_move", | |
| x: e.clientX, | |
| y: e.clientY | |
| }); | |
| } | |
| }); | |
| // Setup chat functionality | |
| document.getElementById('chat-send').addEventListener('click', sendChatMessage); | |
| document.getElementById('chat-input').addEventListener('keypress', (e) => { | |
| if (e.key === 'Enter') { | |
| sendChatMessage(); | |
| } | |
| }); | |
| // Update existing button handlers to broadcast events | |
| document.getElementById('run-circuit').addEventListener('click', function() { | |
| // Existing handler code | |
| drawCircuit(); | |
| setTimeout(() => { | |
| drawHistogram(); | |
| drawEvolution(); | |
| }, 500); | |
| // Broadcast the event | |
| room.send({ | |
| type: "run_circuit" | |
| }); | |
| }); | |
| document.getElementById('update-env').addEventListener('click', function() { | |
| // Existing handler code | |
| drawEnvironment(); | |
| setTimeout(() => { | |
| drawEvolution(); | |
| }, 500); | |
| // Broadcast the event | |
| room.send({ | |
| type: "update_env" | |
| }); | |
| }); | |
| document.getElementById('run-analysis').addEventListener('click', function() { | |
| // Existing handler code | |
| drawCircuit(); | |
| setTimeout(() => { | |
| drawEnvironment(); | |
| setTimeout(() => { | |
| drawHistogram(); | |
| setTimeout(() => { | |
| drawEvolution(); | |
| }, 300); | |
| }, 300); | |
| }, 300); | |
| // Broadcast the event | |
| room.send({ | |
| type: "run_analysis" | |
| }); | |
| }); | |
| // Update input handlers to broadcast parameter changes | |
| const parameterInputs = [ | |
| 'num-qubits', 'num-shots', 'time-const', | |
| 'space-scale', 'mass-value', 'dimension-num' | |
| ]; | |
| parameterInputs.forEach(inputId => { | |
| const inputElement = document.getElementById(inputId); | |
| // Store original event handler | |
| const originalHandler = inputElement.onchange; | |
| // Add new handler that broadcasts changes | |
| inputElement.addEventListener('change', function(e) { | |
| // Call original handler if it exists | |
| if (originalHandler) originalHandler(e); | |
| // Broadcast parameter change | |
| room.send({ | |
| type: "parameter_change", | |
| parameter: inputId, | |
| value: parseInt(e.target.value) | |
| }); | |
| }); | |
| }); | |
| // Initialize users list | |
| updateUsersList(); | |
| } | |
| // Add user to the connected users list | |
| function addUserToList(userId, userName) { | |
| if (!userColors[userId]) { | |
| // Assign a random color for this user | |
| const hue = Math.floor(Math.random() * 360); | |
| userColors[userId] = `hsl(${hue}, 70%, 60%)`; | |
| } | |
| updateUsersList(); | |
| } | |
| // Remove user from the connected users list | |
| function removeUserFromList(userId) { | |
| updateUsersList(); | |
| } | |
| // Update the entire users list | |
| function updateUsersList() { | |
| const usersContainer = document.getElementById('users-container'); | |
| usersContainer.innerHTML = ''; | |
| for (const clientId in room.party.peers) { | |
| const { username } = room.party.peers[clientId]; | |
| const color = userColors[clientId] || 'hsl(200, 70%, 60%)'; | |
| const userDiv = document.createElement('div'); | |
| userDiv.className = 'user-container'; | |
| const userAvatar = document.createElement('div'); | |
| userAvatar.className = 'user-avatar'; | |
| userAvatar.style.backgroundColor = color; | |
| const userNameSpan = document.createElement('span'); | |
| userNameSpan.textContent = username; | |
| userDiv.appendChild(userAvatar); | |
| userDiv.appendChild(userNameSpan); | |
| usersContainer.appendChild(userDiv); | |
| } | |
| } | |
| // Update cursor position for a specific user | |
| function updateCursor(userId, x, y, userName) { | |
| // Don't show the current user's cursor | |
| if (userId === clientId) return; | |
| let cursor = cursors[userId]; | |
| if (!cursor) { | |
| // Create cursor element if it doesn't exist | |
| cursor = document.createElement('div'); | |
| cursor.className = 'user-cursor'; | |
| const pointer = document.createElement('div'); | |
| pointer.className = 'cursor-pointer'; | |
| const label = document.createElement('div'); | |
| label.className = 'cursor-label'; | |
| label.textContent = userName; | |
| cursor.appendChild(pointer); | |
| cursor.appendChild(label); | |
| document.body.appendChild(cursor); | |
| cursors[userId] = cursor; | |
| } | |
| // Get user's color or assign a new one | |
| if (!userColors[userId]) { | |
| const hue = Math.floor(Math.random() * 360); | |
| userColors[userId] = `hsl(${hue}, 70%, 60%)`; | |
| } | |
| // Update cursor position and color | |
| cursor.style.left = `${x}px`; | |
| cursor.style.top = `${y}px`; | |
| cursor.querySelector('.cursor-pointer').style.backgroundColor = userColors[userId]; | |
| } | |
| // Remove cursor for a disconnected user | |
| function removeCursor(userId) { | |
| if (cursors[userId]) { | |
| document.body.removeChild(cursors[userId]); | |
| delete cursors[userId]; | |
| } | |
| } | |
| // Send a chat message | |
| function sendChatMessage() { | |
| const inputElement = document.getElementById('chat-input'); | |
| const message = inputElement.value.trim(); | |
| if (message) { | |
| room.send({ | |
| type: "chat", | |
| message: message | |
| }); | |
| addChatMessage(username, message); | |
| inputElement.value = ''; | |
| } | |
| } | |
| // Add a message to the chat box | |
| function addChatMessage(userName, message) { | |
| const messagesContainer = document.getElementById('chat-messages'); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message'; | |
| const userSpan = document.createElement('span'); | |
| userSpan.className = 'message-user'; | |
| userSpan.textContent = `${userName}: `; | |
| const textSpan = document.createElement('span'); | |
| textSpan.className = 'message-text'; | |
| textSpan.textContent = message; | |
| messageDiv.appendChild(userSpan); | |
| messageDiv.appendChild(textSpan); | |
| messagesContainer.appendChild(messageDiv); | |
| // Auto-scroll to the bottom | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| } | |
| // Add a system message | |
| function addSystemMessage(message) { | |
| const messagesContainer = document.getElementById('chat-messages'); | |
| const messageDiv = document.createElement('div'); | |
| messageDiv.className = 'message'; | |
| messageDiv.style.color = '#8cf'; | |
| messageDiv.style.fontStyle = 'italic'; | |
| messageDiv.textContent = message; | |
| messagesContainer.appendChild(messageDiv); | |
| messagesContainer.scrollTop = messagesContainer.scrollHeight; | |
| } | |
| // Handle parameter change events from other users | |
| function handleParameterChange(paramId, value, userName) { | |
| const inputElement = document.getElementById(paramId); | |
| if (inputElement) { | |
| inputElement.value = value; | |
| // Update the state accordingly | |
| if (paramId === 'num-qubits') { | |
| state.qubits = value; | |
| drawCircuit(); | |
| drawHistogram(); | |
| drawEvolution(); | |
| } else if (paramId === 'num-shots') { | |
| state.shots = value; | |
| drawHistogram(); | |
| } else if (paramId === 'time-const') { | |
| state.environmentParams.t = value; | |
| drawEnvironment(); | |
| } else if (paramId === 'space-scale') { | |
| state.environmentParams.s = value; | |
| drawEnvironment(); | |
| } else if (paramId === 'mass-value') { | |
| state.environmentParams.m = value; | |
| drawEnvironment(); | |
| } else if (paramId === 'dimension-num') { | |
| state.environmentParams.d = value; | |
| drawEnvironment(); | |
| } | |
| addSystemMessage(`${userName} changed ${paramId} to ${value}`); | |
| } | |
| } | |
| // Handle run circuit events from other users | |
| function handleRunCircuit(userName) { | |
| addSystemMessage(`${userName} ran the quantum circuit`); | |
| } | |
| // Handle update environment events from other users | |
| function handleUpdateEnv(userName) { | |
| addSystemMessage(`${userName} updated the environment`); | |
| } | |
| // Handle run analysis events from other users | |
| function handleRunAnalysis(userName) { | |
| addSystemMessage(`${userName} ran a full analysis`); | |
| } | |
| // Modify the initialize function to include multiplayer | |
| function initialize() { | |
| // Set up input event handlers | |
| document.getElementById('num-qubits').addEventListener('change', function(e) { | |
| state.qubits = parseInt(e.target.value); | |
| drawCircuit(); | |
| drawHistogram(); | |
| drawEvolution(); | |
| }); | |
| document.getElementById('num-shots').addEventListener('change', function(e) { | |
| state.shots = parseInt(e.target.value); | |
| drawHistogram(); | |
| }); | |
| document.getElementById('time-const').addEventListener('change', function(e) { | |
| state.environmentParams.t = parseInt(e.target.value); | |
| drawEnvironment(); | |
| }); | |
| document.getElementById('space-scale').addEventListener('change', function(e) { | |
| state.environmentParams.s = parseInt(e.target.value); | |
| drawEnvironment(); | |
| }); | |
| document.getElementById('mass-value').addEventListener('change', function(e) { | |
| state.environmentParams.m = parseInt(e.target.value); | |
| drawEnvironment(); | |
| }); | |
| document.getElementById('dimension-num').addEventListener('change', function(e) { | |
| state.environmentParams.d = parseInt(e.target.value); | |
| drawEnvironment(); | |
| }); | |
| // Set up button event handlers | |
| document.getElementById('run-circuit').addEventListener('click', function() { | |
| // Simulate running circuit | |
| drawCircuit(); | |
| setTimeout(() => { | |
| drawHistogram(); | |
| drawEvolution(); | |
| }, 500); | |
| }); | |
| document.getElementById('update-env').addEventListener('click', function() { | |
| // Simulate updating environment | |
| drawEnvironment(); | |
| setTimeout(() => { | |
| drawEvolution(); | |
| }, 500); | |
| }); | |
| document.getElementById('run-analysis').addEventListener('click', function() { | |
| // Simulate full analysis | |
| drawCircuit(); | |
| setTimeout(() => { | |
| drawEnvironment(); | |
| setTimeout(() => { | |
| drawHistogram(); | |
| setTimeout(() => { | |
| drawEvolution(); | |
| }, 300); | |
| }, 300); | |
| }, 300); | |
| }); | |
| // Initial draw | |
| drawCircuit(); | |
| drawEnvironment(); | |
| drawHistogram(); | |
| drawEvolution(); | |
| // Animation loop for evolution visualization | |
| function animate() { | |
| drawEvolution(); | |
| requestAnimationFrame(animate); | |
| } | |
| animate(); | |
| // Initialize multiplayer functionality | |
| initMultiplayer(); | |
| } | |
| // Handle window resize | |
| window.addEventListener('resize', function() { | |
| for (const canvas of Object.values(canvases)) { | |
| canvas.width = canvas.clientWidth; | |
| canvas.height = canvas.clientHeight; | |
| } | |
| drawCircuit(); | |
| drawEnvironment(); | |
| drawHistogram(); | |
| drawEvolution(); | |
| }); | |
| // Start the simulation | |
| initialize(); | |
| </script> | |
| </body> | |
| </html> | |