/** * GXS - QuantumNexus - Plugin Visualizations * Handles all visualization logic for quantum simulation results */ // Global namespace to avoid conflicts window.QuantumVisualizer = window.QuantumVisualizer || { // Initialize all visualizations based on plugin data init: function(pluginKey, resultData) { console.log('Initializing visualizations for plugin:', pluginKey); console.log('Result data:', resultData); if (!resultData || resultData.error) { console.log('No valid result data available for visualization'); return; } // Initialize visualizations based on the plugin type switch(pluginKey) { case 'teleport': case 'handshake': console.log('Initializing quantum state visualization'); this.initQuantumStateViz(resultData); break; case 'auth': console.log('Initializing lattice-based authentication visualization'); this.initLatticeAuthViz(resultData); break; case 'qrng': console.log('Initializing enhanced QRNG visualization'); this.initQRNG(resultData, pluginKey); break; case 'bb84': console.log('Initializing bit distribution visualization'); this.initBitDistribution(resultData, pluginKey); break; case 'grover': case 'quantum_decryption_grover': console.log('Initializing probability distribution visualization'); this.initProbabilityDistribution(resultData, pluginKey); break; case 'vqe': console.log('Initializing energy convergence visualization'); this.initEnergyConvergence(resultData); break; default: // For other plugins, just log that no specific visualization is available console.log('No specific visualization for plugin type: ' + pluginKey); } }, initLatticeAuthViz: function(resultData) { console.log('Setting up lattice-based authentication visualizations'); // Get the output data from the result const outputData = resultData.output || {}; // Create the lattice visualization from base64 image if provided if (outputData.lattice_viz) { this.createLatticeVizFromImage(outputData.lattice_viz); } // Create the authentication protocol visualization this.createAuthProtocolViz(outputData); // Initialize quantum state visualization for compatibility this.initQuantumStateViz(resultData); // Create security strength visualization this.createSecurityStrengthViz(outputData); }, // Create lattice visualization from base64 image createLatticeVizFromImage: function(base64Data) { const container = document.getElementById('lattice-visualization'); if (!container) { console.warn('Lattice visualization container not found'); return; } // Clear existing content container.innerHTML = ''; // Create the image element const img = document.createElement('img'); img.src = 'data:image/png;base64,' + base64Data; img.className = 'img-fluid rounded'; img.alt = 'Lattice Coefficient Distribution'; // Add the image to the container container.appendChild(img); // Add explanation text const explanation = document.createElement('div'); explanation.className = 'mt-3 text-center lattice-explanation'; explanation.innerHTML = `

The lattice visualization shows the distribution of coefficients used in the Ring-LWE cryptographic system. These coefficients form the mathematical foundation of the post-quantum secure authentication protocol.

`; container.appendChild(explanation); console.log('Lattice visualization created from base64 image'); }, // Create authentication protocol visualization createAuthProtocolViz: function(outputData) { const container = document.getElementById('auth-protocol-visualization'); if (!container) { console.warn('Auth protocol visualization container not found'); return; } // Clear existing content container.innerHTML = ''; // Create auth status banner const authSuccess = outputData.auth_success; const statusBanner = document.createElement('div'); statusBanner.className = 'auth-status-banner text-center p-3 mb-4 rounded ' + (authSuccess ? 'bg-success' : 'bg-danger'); statusBanner.innerHTML = `

Authentication ${authSuccess ? 'Successful' : 'Failed'}

`; container.appendChild(statusBanner); // Create protocol steps visualization const protocolSteps = document.createElement('div'); protocolSteps.className = 'protocol-steps'; // Define the steps of the lattice authentication protocol const steps = [ { icon: 'key', title: 'Key Generation', description: 'Generate public and private keys based on lattice problems', details: 'A lattice-based key pair is generated using the Ring-LWE (Ring Learning With Errors) problem. The public key consists of two polynomials (a,b), where b = a*s + e, with s being the private key and e a small error term.' }, { icon: 'question-circle', title: 'Challenge Creation', description: 'Verifier creates a mathematical challenge based on the public key', details: 'The verifier creates a challenge consisting of two polynomials (u,v), where u = a*r + e₁ and v = b*r + e₂. Here r, e₁, and e₂ are small error polynomials only known to the verifier.' }, { icon: 'reply', title: 'Response Computation', description: 'Prover computes response using private key', details: 'The prover uses their private key s to compute w = v - u*s ≈ e₂ - e₁*s. From this, they can extract an approximation of r and hash it to create the response.' }, { icon: 'check-circle', title: 'Verification', description: 'Verifier checks if the response matches the expected value', details: 'The verifier compares the prover\'s hashed response with the hash of the original r polynomial. If they match, authentication succeeds.' } ]; // Create the step cards steps.forEach((step, index) => { const stepCard = document.createElement('div'); stepCard.className = 'card mb-3 protocol-step'; stepCard.innerHTML = `
${index + 1}
${step.title}

${step.description}

${step.details}
`; protocolSteps.appendChild(stepCard); }); container.appendChild(protocolSteps); // Add comparison with traditional crypto const comparison = document.createElement('div'); comparison.className = 'crypto-comparison mt-4 p-3 bg-light rounded'; comparison.innerHTML = `
Post-Quantum Security Advantage
Traditional Cryptography

RSA and ECC rely on integer factorization and discrete logarithm problems that can be efficiently solved by quantum computers using Shor's algorithm.

Lattice-Based Cryptography

Based on the hardness of solving lattice problems that remain difficult even for quantum computers, making it a foundation for post-quantum security.

`; container.appendChild(comparison); console.log('Authentication protocol visualization created'); }, // Create security strength visualization createSecurityStrengthViz: function(outputData) { const container = document.getElementById('security-strength-visualization'); if (!container) { console.warn('Security strength visualization container not found'); return; } // Clear existing content container.innerHTML = ''; // Security levels comparison const securityLevels = document.createElement('div'); securityLevels.className = 'security-levels'; // Create a canvas for the security strength chart const canvas = document.createElement('canvas'); canvas.id = 'security-strength-chart'; canvas.height = 250; securityLevels.appendChild(canvas); // Add the security levels to the container container.appendChild(securityLevels); // Create the security strength chart const ctx = canvas.getContext('2d'); // Security strength data (bits) const securityData = { labels: ['RSA-2048', 'ECC-256', 'AES-256', 'Lattice-Based (n=512)', 'Lattice-Based (n=1024)'], datasets: [ { label: 'Classical Security (bits)', data: [112, 128, 256, 128, 256], backgroundColor: 'rgba(54, 162, 235, 0.5)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 }, { label: 'Quantum Security (bits)', data: [0, 0, 128, 128, 256], // RSA and ECC are broken by quantum computers backgroundColor: 'rgba(255, 99, 132, 0.5)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 } ] }; new Chart(ctx, { type: 'bar', data: securityData, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, title: { display: true, text: 'Security Strength (bits)' } }, x: { title: { display: true, text: 'Cryptographic Algorithm' } } }, plugins: { legend: { position: 'top', }, tooltip: { callbacks: { afterLabel: function(context) { const datasetIndex = context.datasetIndex; const dataIndex = context.dataIndex; if (datasetIndex === 1 && dataIndex <= 1 && context.raw === 0) { return 'Vulnerable to quantum attacks'; } } } } } } }); // Add explanation const explanation = document.createElement('div'); explanation.className = 'mt-3 security-explanation alert alert-info'; explanation.innerHTML = `
Security Strength Explanation

Quantum Security: Lattice-based cryptography maintains its security level even against quantum computers, while traditional methods like RSA and ECC are compromised by quantum algorithms like Shor's.

NIST Standardization: Lattice-based cryptography forms the foundation of several NIST post-quantum cryptography standards, acknowledging its robustness against both classical and quantum attacks.

`; container.appendChild(explanation); console.log('Security strength visualization created'); }, // Existing implementation for bit distribution visualization initBitDistribution: function(resultData, pluginKey) { const chartContainer = document.getElementById('bit-distribution-chart'); if (!chartContainer) return; try { let bitData = []; let bitLabels = ['0', '1']; if (pluginKey === 'qrng' && resultData.output && resultData.output.bitseq) { // Process QRNG bit sequence const bitSeq = resultData.output.bitseq; const zeroes = bitSeq.filter(bit => bit === 0).length; const ones = bitSeq.filter(bit => bit === 1).length; bitData = [zeroes, ones]; } else if (pluginKey === 'bb84' && resultData.output && resultData.output.shared_key) { // Process BB84 shared key const sharedKey = resultData.output.shared_key; const zeroes = sharedKey.filter(bit => bit === 0).length; const ones = sharedKey.filter(bit => bit === 1).length; bitData = [zeroes, ones]; } else { // Default data for demonstration if no real data available bitData = [Math.floor(Math.random() * 5) + 3, Math.floor(Math.random() * 5) + 3]; } // Create chart const ctx = chartContainer.getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: bitLabels, datasets: [{ label: 'Bit Count', data: bitData, backgroundColor: ['rgba(54, 162, 235, 0.5)', 'rgba(255, 99, 132, 0.5)'], borderColor: ['rgba(54, 162, 235, 1)', 'rgba(255, 99, 132, 1)'], borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, ticks: { precision: 0 } } } } }); // Add this line to invoke the enhanced BB84 visualizations if (pluginKey === 'bb84' && resultData.output) { this.createBB84EnhancedVisualizations(resultData.output); } } catch (e) { console.error('Error initializing bit distribution chart:', e); chartContainer.innerHTML = '
Failed to initialize chart
'; } }, // Initialize Bloch sphere for quantum state visualization initQuantumStateViz: function(resultData) { const vizContainer = document.getElementById('quantum-state-viz'); if (!vizContainer) return; try { // Clear any existing content vizContainer.innerHTML = ''; // Create a canvas element const canvas = document.createElement('canvas'); canvas.width = vizContainer.clientWidth || 300; canvas.height = vizContainer.clientHeight || 300; vizContainer.appendChild(canvas); // Get the 2D context const ctx = canvas.getContext('2d'); const centerX = canvas.width / 2; const centerY = canvas.height / 2; const radius = Math.min(centerX, centerY) - 20; // Set background ctx.fillStyle = '#141424'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw the Bloch sphere (simplified 2D representation) // Draw the circle ctx.beginPath(); ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI); ctx.strokeStyle = '#444'; ctx.lineWidth = 2; ctx.stroke(); // Draw the axes ctx.beginPath(); // Z-axis (vertical) ctx.moveTo(centerX, centerY - radius); ctx.lineTo(centerX, centerY + radius); // X-axis (horizontal) ctx.moveTo(centerX - radius, centerY); ctx.lineTo(centerX + radius, centerY); ctx.strokeStyle = '#888'; ctx.lineWidth = 1; ctx.stroke(); // Add labels ctx.font = '14px Arial'; ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.fillText('|0>', centerX, centerY - radius - 10); ctx.fillText('|1>', centerX, centerY + radius + 20); ctx.fillText('|+>', centerX + radius + 20, centerY); ctx.fillText('|->', centerX - radius - 20, centerY); // Draw state vector based on result data let theta = Math.PI / 4; // Default angle if no data let phi = 0; // Extract state from result data if available if (resultData.output && resultData.output.final_state) { // Get the state data const stateData = resultData.output.final_state; if (Array.isArray(stateData) && stateData.length >= 2) { // Calculate theta and phi from state vector const alpha = stateData[0]; const beta = stateData[1]; const alphaAbs = typeof alpha === 'object' ? Math.sqrt(alpha.real**2 + alpha.imag**2) : Math.abs(alpha); theta = 2 * Math.acos(alphaAbs); if (alphaAbs < 0.9999 && Math.abs(beta) > 0.0001) { if (typeof beta === 'object' && typeof alpha === 'object') { phi = Math.atan2(beta.imag, beta.real) - Math.atan2(alpha.imag, alpha.real); } else { phi = beta >= 0 ? 0 : Math.PI; } } } } else if (resultData.output && resultData.output.fingerprint) { // For auth plugin, use fingerprint to represent state const fingerprint = resultData.output.fingerprint; // Calculate theta and phi based on fingerprint values let stateVector = [0, 0, 0]; // Default state // Convert fingerprint to a 3D vector if (fingerprint.length >= 3) { // Use first 3 bits to determine state vector components stateVector = [ fingerprint[0] === 1 ? 0.5 : -0.5, fingerprint[1] === 1 ? 0.5 : -0.5, fingerprint[2] === 1 ? 0.5 : -0.5 ]; } else if (fingerprint.length > 0) { // With fewer bits, use simple mapping if (fingerprint[0] === 1) { // Map to |+> state theta = Math.PI/2; phi = 0; } else { // Map to |0> state theta = 0; phi = 0; } } // Only calculate theta/phi from vector if we didn't set it directly above if (fingerprint.length >= 3) { // Normalize the vector const magnitude = Math.sqrt(stateVector[0]**2 + stateVector[1]**2 + stateVector[2]**2); const normalizedVector = stateVector.map(v => v/magnitude); // Convert to spherical coordinates theta = Math.acos(normalizedVector[2]); phi = Math.atan2(normalizedVector[1], normalizedVector[0]); } } // Convert spherical coordinates to 2D projection const x = radius * Math.sin(theta) * Math.cos(phi); const y = radius * Math.sin(theta) * Math.sin(phi); const z = radius * Math.cos(theta); // Project 3D point onto 2D const projX = centerX + x; const projY = centerY - z; // Negative to match conventional coordinates // Draw the state vector ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(projX, projY); ctx.strokeStyle = '#ff3366'; ctx.lineWidth = 3; ctx.stroke(); // Draw arrowhead const headSize = 10; const angle = Math.atan2(projY - centerY, projX - centerX); ctx.beginPath(); ctx.moveTo(projX, projY); ctx.lineTo( projX - headSize * Math.cos(angle - Math.PI/6), projY - headSize * Math.sin(angle - Math.PI/6) ); ctx.lineTo( projX - headSize * Math.cos(angle + Math.PI/6), projY - headSize * Math.sin(angle + Math.PI/6) ); ctx.closePath(); ctx.fillStyle = '#ff3366'; ctx.fill(); // Display state information ctx.fillStyle = '#fff'; ctx.font = '12px Arial'; ctx.textAlign = 'left'; ctx.fillText(`theta: ${(theta * 180 / Math.PI).toFixed(1)}°`, 10, 20); ctx.fillText(`phi: ${(phi * 180 / Math.PI).toFixed(1)}°`, 10, 40); // For auth plugin, add explanation about lattice-state mapping if (resultData.output && resultData.output.fingerprint) { ctx.fillStyle = 'rgba(255, 255, 255, 0.7)'; ctx.fillRect(10, canvas.height - 70, canvas.width - 20, 60); ctx.fillStyle = '#000'; ctx.font = '11px Arial'; ctx.textAlign = 'center'; ctx.fillText('Lattice Coefficient Representation', centerX, canvas.height - 55); ctx.fillText('The lattice coefficients from the authentication protocol', centerX, canvas.height - 40); ctx.fillText('are mapped to this quantum state for visualization.', centerX, canvas.height - 25); } console.log("Successfully rendered 2D Bloch sphere visualization"); } catch (e) { console.error('Error initializing quantum state visualization:', e); // Display error message in the container vizContainer.innerHTML = '
Failed to initialize visualization
'; } }, // New function to create enhanced BB84 visualizations createBB84EnhancedVisualizations: function(outputData) { // Create container for enhanced visualizations if it doesn't exist let enhancedContainer = document.getElementById('bb84-enhanced-viz'); // If container doesn't exist, create and add it to the DOM if (!enhancedContainer) { // Find the parent container (likely the tab content) const parentContainer = document.getElementById('visualization'); if (!parentContainer) return; // Create container enhancedContainer = document.createElement('div'); enhancedContainer.id = 'bb84-enhanced-viz'; enhancedContainer.className = 'row mt-4'; parentContainer.appendChild(enhancedContainer); } else { // Clear existing content enhancedContainer.innerHTML = ''; } // Create visualizations only if we have the enhanced data if (!outputData.transmission_efficiency && !outputData.error_rate) { // This appears to be the basic BB84 implementation, not the enhanced version return; } // Create Key Metrics visualization this.createKeyMetricsChart(enhancedContainer, outputData); // Create QBER visualization this.createQBERViz(enhancedContainer, outputData); // Create eavesdropper visualization if present if (outputData.eavesdropper_results) { this.createEavesdropperViz(enhancedContainer, outputData); } // Create key generation pipeline visualization this.createKeyPipelineViz(enhancedContainer, outputData); // Create hardware effect visualization this.createHardwareEffectsViz(enhancedContainer, outputData); }, // Create visualization for key metrics createKeyMetricsChart: function(container, data) { // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header'; cardHeader.textContent = 'BB84 Key Metrics'; const cardBody = document.createElement('div'); cardBody.className = 'card-body'; // Create a container div with fixed height const chartContainer = document.createElement('div'); chartContainer.style.height = '250px'; // Fixed height constraint chartContainer.style.position = 'relative'; // Create canvas for chart inside the container const canvas = document.createElement('canvas'); canvas.id = 'bb84-key-metrics-chart'; chartContainer.appendChild(canvas); cardBody.appendChild(chartContainer); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); // Get key metrics data const rawKeyLength = data.alice_bits ? data.alice_bits.length : 0; const siftedKeyLength = data.shared_key ? data.shared_key.length : 0; const finalKeyLength = data.final_key ? data.final_key.length : 0; // Create chart with explicit maintainAspectRatio: false const ctx = canvas.getContext('2d'); new Chart(ctx, { type: 'bar', data: { labels: ['Raw Key', 'Sifted Key', 'Final Secure Key'], datasets: [{ label: 'Bits', data: [rawKeyLength, siftedKeyLength, finalKeyLength], backgroundColor: [ 'rgba(54, 162, 235, 0.5)', 'rgba(75, 192, 192, 0.5)', 'rgba(153, 102, 255, 0.5)' ], borderColor: [ 'rgba(54, 162, 235, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)' ], borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, title: { display: true, text: 'Number of Bits' } } }, plugins: { tooltip: { callbacks: { afterLabel: function(context) { const index = context.dataIndex; if (index === 0) { return `Original bits generated`; } else if (index === 1) { const efficiency = (siftedKeyLength / rawKeyLength * 100).toFixed(1); return `${efficiency}% of raw key (after basis reconciliation)`; } else if (index === 2) { const efficiency = finalKeyLength > 0 ? (finalKeyLength / rawKeyLength * 100).toFixed(1) : 0; return `${efficiency}% of raw key (after privacy amplification)`; } } } } } } }); }, createQBERViz: function(container, data) { // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header'; cardHeader.textContent = 'Error Analysis'; const cardBody = document.createElement('div'); cardBody.className = 'card-body'; // Create a height-constrained wrapper for the chart const chartWrapper = document.createElement('div'); chartWrapper.style.height = '200px'; // Fixed height chartWrapper.style.position = 'relative'; chartWrapper.style.width = '100%'; // Create canvas for chart (inside the wrapper) const canvas = document.createElement('canvas'); canvas.id = 'bb84-qber-chart'; chartWrapper.appendChild(canvas); cardBody.appendChild(chartWrapper); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); // Get error rate data const qber = data.error_rate || 0; const securityThreshold = 0.11; // BB84 security threshold // Determine whether QBER indicates eavesdropping const indicatesEavesdropping = qber > securityThreshold; // Calculate remaining error rate after reconciliation const remainingErrorRate = data.reconciliation_results ? data.reconciliation_results.remaining_error_rate || 0 : 0; // Add QBER interpretation text const interpretation = document.createElement('div'); interpretation.className = 'mt-3 text-center'; if (indicatesEavesdropping) { interpretation.innerHTML = `
QBER: ${(qber * 100).toFixed(2)}% - Above security threshold (${(securityThreshold * 100).toFixed(2)}%)
Possible eavesdropping detected!
`; } else { interpretation.innerHTML = `
QBER: ${(qber * 100).toFixed(2)}% - Below security threshold (${(securityThreshold * 100).toFixed(2)}%)
No evidence of eavesdropping
`; } cardBody.appendChild(interpretation); // Add note about information reconciliation if available if (data.reconciliation_results) { const reconciliation = document.createElement('div'); reconciliation.className = 'mt-2 small text-muted'; reconciliation.innerHTML = `After information reconciliation: ${(remainingErrorRate * 100).toFixed(4)}% error rate`; cardBody.appendChild(reconciliation); } }, // Create visualization for eavesdropper detection createEavesdropperViz: function(container, data) { // Only create if we have eavesdropper data if (!data.eavesdropper_results) return; const eveResults = data.eavesdropper_results; // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header bg-danger text-white'; cardHeader.innerHTML = ' Eavesdropper Analysis'; const cardBody = document.createElement('div'); cardBody.className = 'card-body'; // Create eavesdropper metrics display const eveMetrics = document.createElement('div'); // Add eavesdropper strategy const strategy = document.createElement('div'); strategy.className = 'mb-3'; strategy.innerHTML = ` Attack Strategy: ${data.eve_strategy || 'intercept_resend'}
`; eveMetrics.appendChild(strategy); // Add information leakage metric const leakage = document.createElement('div'); leakage.className = 'mb-3'; const leakageRatio = eveResults.information_leak_ratio || 0; leakage.innerHTML = ` Information Leakage: ${(leakageRatio * 100).toFixed(1)}%
`; eveMetrics.appendChild(leakage); // Add detection probability const detection = document.createElement('div'); detection.className = 'mb-3'; const detectionProb = eveResults.detection_probability || 0; detection.innerHTML = ` Detection Probability: ${(detectionProb * 100).toFixed(1)}%
`; eveMetrics.appendChild(detection); // Add detection status const detectionStatus = document.createElement('div'); detectionStatus.className = 'alert ' + (eveResults.eve_detected ? 'alert-success' : 'alert-warning'); detectionStatus.innerHTML = eveResults.eve_detected ? ' Eavesdropper detected!' : ' Eavesdropper not detected'; eveMetrics.appendChild(detectionStatus); cardBody.appendChild(eveMetrics); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); }, // Create visualization for key generation pipeline createKeyPipelineViz: function(container, data) { // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header'; cardHeader.textContent = 'Key Generation Pipeline'; const cardBody = document.createElement('div'); cardBody.className = 'card-body pb-0'; // Create pipeline visualization const pipeline = document.createElement('div'); pipeline.className = 'key-pipeline'; // Step 1: Quantum Transmission const rawKeyLength = data.alice_bits ? data.alice_bits.length : 0; const transmissionEfficiency = data.transmission_efficiency || 1; const step1 = document.createElement('div'); step1.className = 'pipeline-step mb-4'; step1.innerHTML = `
1 Quantum Transmission ${Math.round(transmissionEfficiency * 100)}% efficiency
${Math.round(rawKeyLength * transmissionEfficiency)} qubits received
`; pipeline.appendChild(step1); // Step 2: Basis Reconciliation const siftedKeyLength = data.shared_key ? data.shared_key.length : 0; const siftedRatio = rawKeyLength > 0 ? siftedKeyLength / rawKeyLength : 0; const step2 = document.createElement('div'); step2.className = 'pipeline-step mb-4'; step2.innerHTML = `
2 Basis Reconciliation ${Math.round(siftedRatio * 100)}% retention
${siftedKeyLength} matching bases
`; pipeline.appendChild(step2); // Step 3: Information Reconciliation if (data.reconciliation_results) { const reconciliationSuccess = data.reconciliation_results.success; const bitsUsed = data.reconciliation_results.bits_used || 0; const correctedBits = data.reconciliation_results.corrected_bits || 0; const remainingErrors = data.reconciliation_results.remaining_error_rate || 0; const reconciliationRatio = siftedKeyLength > 0 ? (siftedKeyLength - bitsUsed) / siftedKeyLength : 0; const step3 = document.createElement('div'); step3.className = 'pipeline-step mb-4'; step3.innerHTML = `
3 Information Reconciliation ${Math.round(reconciliationRatio * 100)}% retention
${siftedKeyLength - bitsUsed} bits
`; pipeline.appendChild(step3); } // Step 4: Privacy Amplification if (data.final_key) { const finalKeyLength = data.final_key.length; const finalRatio = siftedKeyLength > 0 ? finalKeyLength / siftedKeyLength : 0; const step4 = document.createElement('div'); step4.className = 'pipeline-step mb-4'; step4.innerHTML = `
4 Privacy Amplification ${Math.round(finalRatio * 100)}% retention
${finalKeyLength} bits
`; pipeline.appendChild(step4); } cardBody.appendChild(pipeline); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); }, // Create visualization for hardware effects createHardwareEffectsViz: function(container, data) { // Only create if we have noise model data if (!data.noise_model) return; // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header'; const distanceInfo = data.distance_km ? ` (${data.distance_km}km)` : ''; cardHeader.textContent = `Hardware Effects: ${data.hardware_type || 'fiber'}${distanceInfo}`; const cardBody = document.createElement('div'); cardBody.className = 'card-body'; // Extract hardware parameters const noiseModel = data.noise_model; const secureKeyRate = data.secure_key_rate || 0; // Create metrics table const table = document.createElement('table'); table.className = 'table table-sm'; const tbody = document.createElement('tbody'); // Add photon loss row const photonLossRow = document.createElement('tr'); photonLossRow.innerHTML = ` Photon Loss ${(noiseModel.photon_loss * 100).toFixed(2)}%
`; tbody.appendChild(photonLossRow); // Add polarization drift row const polarizationRow = document.createElement('tr'); polarizationRow.innerHTML = ` Polarization Drift ${(noiseModel.polarization_drift * 100).toFixed(2)}%
`; tbody.appendChild(polarizationRow); // Add phase drift row const phaseRow = document.createElement('tr'); phaseRow.innerHTML = ` Phase Drift ${(noiseModel.phase_drift * 100).toFixed(2)}%
`; tbody.appendChild(phaseRow); // Add detector efficiency row const detectorRow = document.createElement('tr'); detectorRow.innerHTML = ` Detector Efficiency ${(noiseModel.detector_efficiency * 100).toFixed(2)}%
`; tbody.appendChild(detectorRow); table.appendChild(tbody); cardBody.appendChild(table); // Add theoretical key rate const keyRateDiv = document.createElement('div'); keyRateDiv.className = 'alert alert-primary mt-2 mb-0'; keyRateDiv.innerHTML = ` Theoretical Secure Key Rate: ${secureKeyRate.toFixed(2)} bits/second
`; cardBody.appendChild(keyRateDiv); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); }, // Create visualization for key generation pipeline createKeyPipelineViz: function(container, data) { // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header'; cardHeader.textContent = 'Key Generation Pipeline'; const cardBody = document.createElement('div'); cardBody.className = 'card-body pb-0'; // Create pipeline visualization const pipeline = document.createElement('div'); pipeline.className = 'key-pipeline'; // Step 1: Quantum Transmission const rawKeyLength = data.alice_bits ? data.alice_bits.length : 0; const transmissionEfficiency = data.transmission_efficiency || 1; const step1 = document.createElement('div'); step1.className = 'pipeline-step mb-4'; step1.innerHTML = `
1 Quantum Transmission ${Math.round(transmissionEfficiency * 100)}% efficiency
${Math.round(rawKeyLength * transmissionEfficiency)} qubits received
`; pipeline.appendChild(step1); // Step 2: Basis Reconciliation const siftedKeyLength = data.shared_key ? data.shared_key.length : 0; const siftedRatio = rawKeyLength > 0 ? siftedKeyLength / rawKeyLength : 0; const step2 = document.createElement('div'); step2.className = 'pipeline-step mb-4'; step2.innerHTML = `
2 Basis Reconciliation ${Math.round(siftedRatio * 100)}% retention
${siftedKeyLength} matching bases
`; pipeline.appendChild(step2); // Step 3: Information Reconciliation if (data.reconciliation_results) { const reconciliationSuccess = data.reconciliation_results.success; const bitsUsed = data.reconciliation_results.bits_used || 0; const correctedBits = data.reconciliation_results.corrected_bits || 0; const remainingErrors = data.reconciliation_results.remaining_error_rate || 0; const reconciliationRatio = siftedKeyLength > 0 ? (siftedKeyLength - bitsUsed) / siftedKeyLength : 0; const step3 = document.createElement('div'); step3.className = 'pipeline-step mb-4'; step3.innerHTML = `
3 Information Reconciliation ${Math.round(reconciliationRatio * 100)}% retention
${siftedKeyLength - bitsUsed} bits
`; pipeline.appendChild(step3); } // Step 4: Privacy Amplification if (data.final_key) { const finalKeyLength = data.final_key.length; const finalRatio = siftedKeyLength > 0 ? finalKeyLength / siftedKeyLength : 0; const step4 = document.createElement('div'); step4.className = 'pipeline-step mb-4'; step4.innerHTML = `
4 Privacy Amplification ${Math.round(finalRatio * 100)}% retention
${finalKeyLength} bits
`; pipeline.appendChild(step4); } cardBody.appendChild(pipeline); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); }, // Create visualization for hardware effects createHardwareEffectsViz: function(container, data) { // Only create if we have noise model data if (!data.noise_model) return; // Create card for the visualization const cardContainer = document.createElement('div'); cardContainer.className = 'col-md-6 mb-4'; const card = document.createElement('div'); card.className = 'card h-100'; const cardHeader = document.createElement('div'); cardHeader.className = 'card-header'; const distanceInfo = data.distance_km ? ` (${data.distance_km}km)` : ''; cardHeader.textContent = `Hardware Effects: ${data.hardware_type || 'fiber'}${distanceInfo}`; const cardBody = document.createElement('div'); cardBody.className = 'card-body'; // Extract hardware parameters const noiseModel = data.noise_model; const secureKeyRate = data.secure_key_rate || 0; // Create metrics table const table = document.createElement('table'); table.className = 'table table-sm'; const tbody = document.createElement('tbody'); // Add photon loss row const photonLossRow = document.createElement('tr'); photonLossRow.innerHTML = ` Photon Loss ${(noiseModel.photon_loss * 100).toFixed(2)}%
`; tbody.appendChild(photonLossRow); // Add polarization drift row const polarizationRow = document.createElement('tr'); polarizationRow.innerHTML = ` Polarization Drift ${(noiseModel.polarization_drift * 100).toFixed(2)}%
`; tbody.appendChild(polarizationRow); // Add phase drift row const phaseRow = document.createElement('tr'); phaseRow.innerHTML = ` Phase Drift ${(noiseModel.phase_drift * 100).toFixed(2)}%
`; tbody.appendChild(phaseRow); // Add detector efficiency row const detectorRow = document.createElement('tr'); detectorRow.innerHTML = ` Detector Efficiency ${(noiseModel.detector_efficiency * 100).toFixed(2)}%
`; tbody.appendChild(detectorRow); table.appendChild(tbody); cardBody.appendChild(table); // Add theoretical key rate const keyRateDiv = document.createElement('div'); keyRateDiv.className = 'alert alert-primary mt-2 mb-0'; keyRateDiv.innerHTML = ` Theoretical Secure Key Rate: ${secureKeyRate.toFixed(2)} bits/second
`; cardBody.appendChild(keyRateDiv); // Assemble card card.appendChild(cardHeader); card.appendChild(cardBody); cardContainer.appendChild(card); container.appendChild(cardContainer); }, // Initialize energy convergence chart for VQE initEnergyConvergence: function(resultData) { const chartContainer = document.getElementById('energy-convergence'); if (!chartContainer) return; try { let iterations = []; let energyValues = []; if (resultData.output && resultData.output.energy_iterations) { // Use actual energy iteration data if available energyValues = resultData.output.energy_iterations; iterations = Array.from({length: energyValues.length}, (_, i) => i + 1); } else { // Create mock energy convergence data for demonstration iterations = Array.from({length: 10}, (_, i) => i + 1); // Simulate decreasing energy values converging to a minimum energyValues = iterations.map(i => 1.0 / (i + 1) + 0.1 * Math.random()); } // Create chart const ctx = chartContainer.getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: iterations, datasets: [{ label: 'Energy', data: energyValues, borderColor: 'rgba(75, 192, 192, 1)', backgroundColor: 'rgba(75, 192, 192, 0.2)', tension: 0.1, fill: true }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { title: { display: true, text: 'Energy' } }, x: { title: { display: true, text: 'Iteration' } } } } }); } catch (e) { console.error('Error initializing energy convergence chart:', e); chartContainer.innerHTML = '
Failed to initialize chart
'; } }, // Deutsch-Jozsa visualization initDeutschJozsaVisualization: function(resultData) { const vizContainer = document.getElementById('deutsch-jozsa-viz'); if (!vizContainer) return; try { // Clear any existing content vizContainer.innerHTML = ''; // Create canvas for oracle type visualization const canvas = document.createElement('canvas'); canvas.width = vizContainer.clientWidth || 400; canvas.height = vizContainer.clientHeight || 300; vizContainer.appendChild(canvas); // Get the 2D context const ctx = canvas.getContext('2d'); // Get data from the result const output = resultData.output || {}; const oracleType = output.oracle_type || 'unknown'; const isConstant = output.is_function_constant || false; const actualConstant = output.actual_function_constant || false; const correct = output.correct_determination || false; // Set background ctx.fillStyle = '#f8f9fa'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw oracle visualization ctx.textAlign = 'center'; ctx.font = '16px Arial'; ctx.fillStyle = '#333'; ctx.fillText(`Oracle Type: ${oracleType}`, canvas.width/2, 40); // Draw function type box ctx.fillStyle = isConstant ? '#4CAF50' : '#2196F3'; ctx.fillRect(canvas.width/2 - 100, 60, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText(`Determined: ${isConstant ? 'Constant' : 'Balanced'}`, canvas.width/2, 90); // Draw actual function type ctx.fillStyle = actualConstant ? '#4CAF50' : '#2196F3'; ctx.fillRect(canvas.width/2 - 100, 120, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText(`Actual: ${actualConstant ? 'Constant' : 'Balanced'}`, canvas.width/2, 150); // Draw accuracy indicator ctx.fillStyle = correct ? '#4CAF50' : '#F44336'; ctx.fillRect(canvas.width/2 - 100, 180, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText(`Determination: ${correct ? 'Correct' : 'Incorrect'}`, canvas.width/2, 210); // Add explanatory text ctx.fillStyle = '#333'; ctx.textAlign = 'left'; ctx.font = '14px Arial'; ctx.fillText('The Deutsch-Jozsa algorithm determines whether a function is', 20, 250); ctx.fillText('constant or balanced with a single quantum query, showing', 20, 270); ctx.fillText('quantum advantage over classical algorithms.', 20, 290); } catch (e) { console.error('Error creating Deutsch-Jozsa visualization:', e); vizContainer.innerHTML = '
Failed to initialize visualization
'; } }, // QFT visualization initQFTVisualization: function(resultData) { const vizContainer = document.getElementById('qft-state-viz'); if (!vizContainer) return; try { // Clear any existing content vizContainer.innerHTML = ''; // Create canvas for QFT visualization const canvas = document.createElement('canvas'); canvas.width = vizContainer.clientWidth || 400; canvas.height = vizContainer.clientHeight || 300; vizContainer.appendChild(canvas); // Get the 2D context const ctx = canvas.getContext('2d'); // Get data from the result const output = resultData.output || {}; const inputState = output.input_state || ''; const measuredState = output.measured_state || ''; const includeInverse = output.include_inverse || false; // Set background ctx.fillStyle = '#f8f9fa'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw QFT transformation visualization const centerX = canvas.width / 2; const yStart = 70; // Title ctx.textAlign = 'center'; ctx.font = 'bold 18px Arial'; ctx.fillStyle = '#333'; ctx.fillText('Quantum Fourier Transform', centerX, 30); // Input state ctx.fillStyle = '#2196F3'; ctx.fillRect(centerX - 100, yStart, 200, 50); ctx.fillStyle = '#fff'; ctx.font = '16px Arial'; ctx.fillText(`Input: |${inputState}⟩`, centerX, yStart + 30); // Arrow down ctx.fillStyle = '#333'; ctx.beginPath(); ctx.moveTo(centerX, yStart + 60); ctx.lineTo(centerX - 10, yStart + 70); ctx.lineTo(centerX + 10, yStart + 70); ctx.closePath(); ctx.fill(); // QFT operation ctx.fillStyle = '#FF9800'; ctx.fillRect(centerX - 100, yStart + 80, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText('QFT', centerX, yStart + 110); // Arrow down for QFT result or inverse QFT ctx.fillStyle = '#333'; ctx.beginPath(); ctx.moveTo(centerX, yStart + 140); ctx.lineTo(centerX - 10, yStart + 150); ctx.lineTo(centerX + 10, yStart + 150); ctx.closePath(); ctx.fill(); // If inverse is included, show another step if (includeInverse) { ctx.fillStyle = '#9C27B0'; ctx.fillRect(centerX - 100, yStart + 160, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText('Inverse QFT', centerX, yStart + 190); // Arrow down for final result ctx.fillStyle = '#333'; ctx.beginPath(); ctx.moveTo(centerX, yStart + 220); ctx.lineTo(centerX - 10, yStart + 230); ctx.lineTo(centerX + 10, yStart + 230); ctx.closePath(); ctx.fill(); // Final state ctx.fillStyle = '#4CAF50'; ctx.fillRect(centerX - 100, yStart + 240, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText(`Measured: |${measuredState}⟩`, centerX, yStart + 270); // Success indicator if (inputState === measuredState) { ctx.fillStyle = '#4CAF50'; ctx.fillRect(centerX - 100, yStart + 300, 200, 30); ctx.fillStyle = '#fff'; ctx.font = '14px Arial'; ctx.fillText('Successfully recovered input state', centerX, yStart + 320); } else { ctx.fillStyle = '#F44336'; ctx.fillRect(centerX - 100, yStart + 300, 200, 30); ctx.fillStyle = '#fff'; ctx.font = '14px Arial'; ctx.fillText('Input state changed (likely due to noise)', centerX, yStart + 320); } } else { // Fourier basis state ctx.fillStyle = '#4CAF50'; ctx.fillRect(centerX - 100, yStart + 160, 200, 50); ctx.fillStyle = '#fff'; ctx.fillText(`Measured: |${measuredState}⟩`, centerX, yStart + 190); // Explanation ctx.fillStyle = '#333'; ctx.textAlign = 'left'; ctx.font = '14px Arial'; ctx.fillText('The state is now in the Fourier basis,', centerX - 100, yStart + 230); ctx.fillText('encoding frequency information of the input.', centerX - 100, yStart + 250); } } catch (e) { console.error('Error creating QFT visualization:', e); vizContainer.innerHTML = '
Failed to initialize visualization
'; } }, // Phase Estimation visualization initPhaseEstimationVisualization: function(resultData) { const vizContainer = document.getElementById('phase-estimation-viz'); if (!vizContainer) return; try { // Clear any existing content vizContainer.innerHTML = ''; // Create canvas for phase visualization const canvas = document.createElement('canvas'); canvas.width = vizContainer.clientWidth || 400; canvas.height = vizContainer.clientHeight || 300; vizContainer.appendChild(canvas); // Get the 2D context const ctx = canvas.getContext('2d'); // Get data from the result const output = resultData.output || {}; const targetPhase = output.target_phase || 0; const estimatedPhase = output.estimated_phase || 0; const phaseError = output.phase_error || 0; const accuracy = output.theoretical_accuracy || 0; const precisionBits = output.precision_bits || 3; // Set background ctx.fillStyle = '#f8f9fa'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw title ctx.textAlign = 'center'; ctx.font = 'bold 18px Arial'; ctx.fillStyle = '#333'; ctx.fillText('Quantum Phase Estimation', canvas.width/2, 30); // Draw phase circle visualization const centerX = canvas.width / 2; const centerY = 150; const radius = 100; // Draw circle ctx.beginPath(); ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI); ctx.strokeStyle = '#333'; ctx.lineWidth = 2; ctx.stroke(); // Draw center point ctx.beginPath(); ctx.arc(centerX, centerY, 3, 0, 2 * Math.PI); ctx.fillStyle = '#333'; ctx.fill(); // Draw 0 phase marker ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(centerX + radius, centerY); ctx.strokeStyle = '#999'; ctx.lineWidth = 1; ctx.stroke(); // Draw target phase line const targetAngle = targetPhase * 2 * Math.PI; const targetX = centerX + radius * Math.cos(targetAngle); const targetY = centerY + radius * Math.sin(targetAngle); ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(targetX, targetY); ctx.strokeStyle = '#4CAF50'; ctx.lineWidth = 3; ctx.stroke(); // Draw target phase point ctx.beginPath(); ctx.arc(targetX, targetY, 6, 0, 2 * Math.PI); ctx.fillStyle = '#4CAF50'; ctx.fill(); // Draw estimated phase line const estimatedAngle = estimatedPhase * 2 * Math.PI; const estimatedX = centerX + radius * Math.cos(estimatedAngle); const estimatedY = centerY + radius * Math.sin(estimatedAngle); ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(estimatedX, estimatedY); ctx.strokeStyle = '#2196F3'; ctx.lineWidth = 3; ctx.stroke(); // Draw estimated phase point ctx.beginPath(); ctx.arc(estimatedX, estimatedY, 6, 0, 2 * Math.PI); ctx.fillStyle = '#2196F3'; ctx.fill(); // Draw legend and info ctx.textAlign = 'left'; ctx.font = '14px Arial'; ctx.fillStyle = '#333'; // Target phase marker ctx.fillStyle = '#4CAF50'; ctx.fillRect(20, 220, 15, 15); ctx.fillStyle = '#333'; ctx.fillText(`Target phase: ${targetPhase.toFixed(4)}`, 45, 232); // Estimated phase marker ctx.fillStyle = '#2196F3'; ctx.fillRect(20, 245, 15, 15); ctx.fillStyle = '#333'; ctx.fillText(`Estimated phase: ${estimatedPhase.toFixed(4)}`, 45, 257); // Phase error ctx.fillText(`Error: ${phaseError.toFixed(6)}`, 45, 282); // Theoretical accuracy ctx.textAlign = 'right'; ctx.fillText(`Precision bits: ${precisionBits}`, canvas.width - 20, 232); ctx.fillText(`Theoretical accuracy: 1/${Math.pow(2, precisionBits)} = ${accuracy.toFixed(6)}`, canvas.width - 20, 257); // Compare error to theoretical accuracy if (phaseError <= accuracy) { ctx.fillStyle = '#4CAF50'; ctx.fillText('✓ Within theoretical bounds', canvas.width - 20, 282); } else { ctx.fillStyle = '#F44336'; ctx.fillText('✗ Outside theoretical bounds', canvas.width - 20, 282); } } catch (e) { console.error('Error creating Phase Estimation visualization:', e); vizContainer.innerHTML = '
Failed to initialize visualization
'; } }, // Initialize Bloch sphere for quantum state visualization initQuantumStateViz: function(resultData) { const vizContainer = document.getElementById('quantum-state-viz'); if (!vizContainer) return; try { // Clear any existing content vizContainer.innerHTML = ''; // Create a canvas element const canvas = document.createElement('canvas'); canvas.width = vizContainer.clientWidth || 300; canvas.height = vizContainer.clientHeight || 300; vizContainer.appendChild(canvas); // Get the 2D context const ctx = canvas.getContext('2d'); const centerX = canvas.width / 2; const centerY = canvas.height / 2; const radius = Math.min(centerX, centerY) - 20; // Set background ctx.fillStyle = '#141424'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw the Bloch sphere (simplified 2D representation) // Draw the circle ctx.beginPath(); ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI); ctx.strokeStyle = '#444'; ctx.lineWidth = 2; ctx.stroke(); // Draw the axes ctx.beginPath(); // Z-axis (vertical) ctx.moveTo(centerX, centerY - radius); ctx.lineTo(centerX, centerY + radius); // X-axis (horizontal) ctx.moveTo(centerX - radius, centerY); ctx.lineTo(centerX + radius, centerY); ctx.strokeStyle = '#888'; ctx.lineWidth = 1; ctx.stroke(); // Add labels ctx.font = '14px Arial'; ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.fillText('|0>', centerX, centerY - radius - 10); ctx.fillText('|1>', centerX, centerY + radius + 20); ctx.fillText('|+>', centerX + radius + 20, centerY); ctx.fillText('|->', centerX - radius - 20, centerY); // Draw state vector based on result data let theta = Math.PI / 4; // Default angle if no data let phi = 0; // Extract state from result data if available if (resultData.output && resultData.output.final_state) { // Get the state data const stateData = resultData.output.final_state; if (Array.isArray(stateData) && stateData.length >= 2) { // Calculate theta and phi from state vector const alpha = stateData[0]; const beta = stateData[1]; const alphaAbs = typeof alpha === 'object' ? Math.sqrt(alpha.real**2 + alpha.imag**2) : Math.abs(alpha); theta = 2 * Math.acos(alphaAbs); if (alphaAbs < 0.9999 && Math.abs(beta) > 0.0001) { if (typeof beta === 'object' && typeof alpha === 'object') { phi = Math.atan2(beta.imag, beta.real) - Math.atan2(alpha.imag, alpha.real); } else { phi = beta >= 0 ? 0 : Math.PI; } } } } // Convert spherical coordinates to 2D projection const x = radius * Math.sin(theta) * Math.cos(phi); const y = radius * Math.sin(theta) * Math.sin(phi); const z = radius * Math.cos(theta); // Project 3D point onto 2D const projX = centerX + x; const projY = centerY - z; // Negative to match conventional coordinates // Draw the state vector ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(projX, projY); ctx.strokeStyle = '#ff3366'; ctx.lineWidth = 3; ctx.stroke(); // Draw arrowhead const headSize = 10; const angle = Math.atan2(projY - centerY, projX - centerX); ctx.beginPath(); ctx.moveTo(projX, projY); ctx.lineTo( projX - headSize * Math.cos(angle - Math.PI/6), projY - headSize * Math.sin(angle - Math.PI/6) ); ctx.lineTo( projX - headSize * Math.cos(angle + Math.PI/6), projY - headSize * Math.sin(angle + Math.PI/6) ); ctx.closePath(); ctx.fillStyle = '#ff3366'; ctx.fill(); // Display state information ctx.fillStyle = '#fff'; ctx.font = '12px Arial'; ctx.textAlign = 'left'; ctx.fillText(`theta: ${(theta * 180 / Math.PI).toFixed(1)}°`, 10, 20); ctx.fillText(`phi: ${(phi * 180 / Math.PI).toFixed(1)}°`, 10, 40); console.log("Successfully rendered 2D Bloch sphere visualization"); } catch (e) { console.error('Error initializing quantum state visualization:', e); // Display error message in the container vizContainer.innerHTML = '
Failed to initialize visualization
'; } }, initProbabilityDistribution : function(resultData, pluginKey) { const chartContainer = document.getElementById('probability-distribution'); if (!chartContainer) return; try { console.log('Initializing probability distribution chart for', pluginKey); let labels = []; let probData = []; if (pluginKey === 'grover' && resultData.output) { // Extract number of qubits from output or default to 3 const n = resultData.output.n || 3; const targetState = resultData.output.target_state || '101'; const measuredState = resultData.output.measured_state || ''; const numStates = Math.pow(2, n); // Create labels and probability data for (let i = 0; i < numStates; i++) { const stateBinary = i.toString(2).padStart(n, '0'); labels.push(`|${stateBinary}⟩`); // Set high probability for target state and measured state, low for others if (stateBinary === targetState) { probData.push(0.9); // Target state has high probability } else if (stateBinary === measuredState && measuredState !== targetState) { probData.push(0.7); // Actually measured state (if different from target) } else { probData.push(0.1 / (numStates - 1)); // Low probability for other states } } } else if (pluginKey === 'quantum_decryption_grover' && resultData.output) { // Similar handling for quantum_decryption_grover const n = resultData.output.n || 4; const targetState = resultData.output.target_state || '0101'; const numStates = Math.pow(2, n); for (let i = 0; i < numStates; i++) { const stateBinary = i.toString(2).padStart(n, '0'); labels.push(`|${stateBinary}⟩`); probData.push(stateBinary === targetState ? 0.9 : 0.1 / (numStates - 1)); } } else { // Default data for demonstration for (let i = 0; i < 8; i++) { labels.push(`|${i.toString(2).padStart(3, '0')}⟩`); probData.push(Math.random() * 0.2); } // Make one state prominent probData[3] = 0.8; } // Create chart const ctx = chartContainer.getContext('2d'); // Check if Chart is available if (typeof Chart === 'undefined') { console.error('Chart.js library not available'); chartContainer.innerHTML = '
Chart.js library not available
'; return; } // Destroy existing chart if it exists if (window.groverChart) { window.groverChart.destroy(); } window.groverChart = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [{ label: 'Probability', data: probData, backgroundColor: 'rgba(153, 102, 255, 0.5)', borderColor: 'rgba(153, 102, 255, 1)', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, max: 1, title: { display: true, text: 'Probability' } }, x: { title: { display: true, text: 'Quantum States' } } }, plugins: { legend: { display: true, position: 'top' }, tooltip: { callbacks: { label: function(context) { return `Probability: ${context.raw.toFixed(4)}`; } } } } } }); console.log('Probability distribution chart created successfully'); } catch (e) { console.error('Error initializing probability distribution chart:', e); chartContainer.innerHTML = '
Failed to initialize chart
'; } }, // QAOA visualization initQAOAVisualization: function(resultData) { const vizContainer = document.getElementById('qaoa-graph-viz'); if (!vizContainer) return; try { // Clear any existing content vizContainer.innerHTML = ''; // Create canvas for graph visualization const canvas = document.createElement('canvas'); canvas.width = vizContainer.clientWidth || 400; canvas.height = vizContainer.clientHeight || 400; vizContainer.appendChild(canvas); // Get the 2D context const ctx = canvas.getContext('2d'); // Get data from the result const output = resultData.output || {}; const nNodes = output.n_nodes || 4; const graphEdges = output.graph_edges || []; const partition0 = output.partition_0 || []; const partition1 = output.partition_1 || []; const approxRatio = output.approximation_ratio || 0; // Set background ctx.fillStyle = '#f8f9fa'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw title ctx.textAlign = 'center'; ctx.font = 'bold 18px Arial'; ctx.fillStyle = '#333'; ctx.fillText('MaxCut Graph Partitioning', canvas.width/2, 30); // Draw approximation ratio ctx.font = '14px Arial'; ctx.fillText(`Approximation Ratio: ${approxRatio.toFixed(4)}`, canvas.width/2, 55); // Generate node positions in a circle const centerX = canvas.width / 2; const centerY = canvas.height / 2; const radius = Math.min(centerX, centerY) - 60; const nodePositions = {}; for (let i = 0; i < nNodes; i++) { const angle = (i / nNodes) * 2 * Math.PI; nodePositions[i] = { x: centerX + radius * Math.cos(angle), y: centerY + radius * Math.sin(angle) }; } // Draw edges ctx.lineWidth = 2; graphEdges.forEach(edge => { const [i, j] = edge; const startPos = nodePositions[i]; const endPos = nodePositions[j]; // Check if this edge is cut (nodes in different partitions) const isCut = (partition0.includes(i) && partition1.includes(j)) || (partition1.includes(i) && partition0.includes(j)); // Draw edge with appropriate color ctx.beginPath(); ctx.moveTo(startPos.x, startPos.y); ctx.lineTo(endPos.x, endPos.y); ctx.strokeStyle = isCut ? '#e53935' : '#90caf9'; ctx.stroke(); // Add a label for cut edges if (isCut) { const midX = (startPos.x + endPos.x) / 2; const midY = (startPos.y + endPos.y) / 2; ctx.fillStyle = '#e53935'; ctx.textAlign = 'center'; ctx.font = '12px Arial'; ctx.fillText('cut', midX, midY - 5); } }); // Draw nodes const nodeRadius = 20; // Draw partition 0 nodes partition0.forEach(nodeIdx => { const pos = nodePositions[nodeIdx]; ctx.beginPath(); ctx.arc(pos.x, pos.y, nodeRadius, 0, 2 * Math.PI); ctx.fillStyle = '#4CAF50'; ctx.fill(); ctx.strokeStyle = '#333'; ctx.lineWidth = 2; ctx.stroke(); // Add node label ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = 'bold 14px Arial'; ctx.fillText(nodeIdx.toString(), pos.x, pos.y); } ); // Draw partition 1 nodes partition1.forEach(nodeIdx => { const pos = nodePositions[nodeIdx]; ctx.beginPath(); ctx.arc(pos.x, pos.y, nodeRadius, 0, 2 * Math.PI); ctx.fillStyle = '#2196F3'; ctx.fill(); ctx.strokeStyle = '#333'; ctx.lineWidth = 2; ctx.stroke(); // Add node label ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = 'bold 14px Arial'; ctx.fillText(nodeIdx.toString(), pos.x, pos.y); }); // Add legend const legendY = canvas.height - 60; // Partition 0 ctx.beginPath(); ctx.arc(40, legendY, 10, 0, 2 * Math.PI); ctx.fillStyle = '#4CAF50'; ctx.fill(); ctx.strokeStyle = '#333'; ctx.lineWidth = 1; ctx.stroke(); ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; ctx.fillStyle = '#333'; ctx.font = '14px Arial'; ctx.fillText('Partition 0', 60, legendY); // Partition 1 ctx.beginPath(); ctx.arc(160, legendY, 10, 0, 2 * Math.PI); ctx.fillStyle = '#2196F3'; ctx.fill(); ctx.strokeStyle = '#333'; ctx.lineWidth = 1; ctx.stroke(); ctx.fillStyle = '#333'; ctx.fillText('Partition 1', 180, legendY); // Cut edge ctx.beginPath(); ctx.moveTo(260, legendY); ctx.lineTo(310, legendY); ctx.strokeStyle = '#e53935'; ctx.lineWidth = 2; ctx.stroke(); ctx.fillStyle = '#333'; ctx.fillText('Cut edge', 320, legendY); } catch (e) { console.error('Error creating QAOA visualization:', e); vizContainer.innerHTML = '
Failed to initialize visualization
'; } }, initQRNG: function(resultData) { if (!resultData || !resultData.output) return; const output = resultData.output; // Find the visualization container const visualizationTab = document.querySelector('#visualization'); if (!visualizationTab) return; // Create enhanced QRNG visualization container if (!document.getElementById('qrng-enhanced-viz')) { const container = document.createElement('div'); container.id = 'qrng-enhanced-viz'; container.className = 'mt-4'; visualizationTab.appendChild(container); // Create comprehensive visualization structure container.innerHTML = `
Quantum Randomness Dashboard
Quality: --

--

Random Number

--

Entropy %

--

Bias

--

Bits/sec
Bit Sequence Visualization
Quantum Source
--

--

Noise Level: 0%
Interactive Controls
Applications
-
`; } // Initialize history if it doesn't exist if (!window.qrngHistory) { window.qrngHistory = []; } // Update the visualization with new data this.updateQRNGVisualization(output); }, updateQRNGVisualization: function(output) { try { // Update main metrics document.getElementById('qrng-random-number').textContent = output.random_number || '--'; // Update quality metrics if (output.statistics && !output.statistics.error) { const stats = output.statistics; document.getElementById('qrng-entropy').textContent = Math.round(stats.entropy_percentage) + '%'; document.getElementById('qrng-bias').textContent = (stats.bias * 100).toFixed(2) + '%'; document.getElementById('qrng-quality-badge').textContent = `Quality: ${Math.round(stats.quality_score)}/100`; // Color code quality badge const qualityBadge = document.getElementById('qrng-quality-badge'); qualityBadge.className = 'badge ' + (stats.quality_score >= 80 ? 'bg-success' : stats.quality_score >= 60 ? 'bg-warning' : 'bg-danger'); } // Update performance metrics if (output.bits_per_second) { document.getElementById('qrng-performance').textContent = Math.round(output.bits_per_second); } // Update source information document.getElementById('qrng-source-name').textContent = output.source_name || 'Unknown'; document.getElementById('qrng-source-description').textContent = output.source_description || ''; // Update noise level const noiseLevel = (output.noise_level * 100).toFixed(1); document.getElementById('qrng-noise-level').textContent = noiseLevel + '%'; document.getElementById('qrng-noise-indicator').style.width = noiseLevel + '%'; // Update bit sequence visualization this.updateBitSequenceVisualization(output); // Update statistical charts this.updateQRNGCharts(output); // Update detailed tabs this.updateQRNGStatisticalTests(output); this.updateQRNGBitDetails(output); this.updateQRNGApplications(output); this.updateQRNGEducationalContent(output); // Add to history this.addToQRNGHistory(output); // Setup event listeners for interactive controls this.setupQRNGControls(output); } catch (error) { console.error('Error updating QRNG visualization:', error); } }, updateBitSequenceVisualization: function(output) { const container = document.getElementById('qrng-bit-sequence'); if (!container) return; const bits = output.bits_string || ''; let html = ''; // Detect theme for better color choices const isDarkMode = document.documentElement.getAttribute('data-theme') === 'quantumdark'; // Create colored bit representation with theme-aware colors for (let i = 0; i < bits.length; i++) { const bit = bits[i]; let bgClass, textClass; if (bit === '1') { bgClass = 'bg-success'; textClass = isDarkMode ? 'text-dark' : 'text-white'; } else { bgClass = isDarkMode ? 'bg-secondary' : 'bg-dark'; textClass = isDarkMode ? 'text-light' : 'text-white'; } html += `${bit}`; } container.innerHTML = html; }, updateQRNGCharts: function(output) { // Distribution Chart this.createDistributionChart(output); // Quality Radar Chart this.createQualityRadarChart(output); }, createDistributionChart: function(output) { const canvas = document.getElementById('qrng-distribution-chart'); if (!canvas) return; const ctx = canvas.getContext('2d'); // Clear previous chart ctx.clearRect(0, 0, canvas.width, canvas.height); if (!output.statistics || output.statistics.error) return; const stats = output.statistics; const zeros = stats.zeros_count; const ones = stats.ones_count; // Detect theme for colors const isDarkMode = document.documentElement.getAttribute('data-theme') === 'quantumdark'; const colors = { zero: isDarkMode ? '#6b7280' : '#3498db', one: isDarkMode ? '#34d399' : '#e74c3c', text: isDarkMode ? '#f9fafb' : '#333333', grid: isDarkMode ? '#4b5563' : '#e5e7eb' }; // Simple bar chart const maxCount = Math.max(zeros, ones); const barWidth = canvas.width / 3; const barHeight = canvas.height - 60; // Draw bars ctx.fillStyle = colors.zero; const zeroHeight = (zeros / maxCount) * barHeight; ctx.fillRect(barWidth / 2, canvas.height - 40 - zeroHeight, barWidth / 2, zeroHeight); ctx.fillStyle = colors.one; const oneHeight = (ones / maxCount) * barHeight; ctx.fillRect(barWidth * 1.5, canvas.height - 40 - oneHeight, barWidth / 2, oneHeight); // Draw labels ctx.fillStyle = colors.text; ctx.font = '12px Inter, Arial, sans-serif'; ctx.textAlign = 'center'; ctx.fillText('0s: ' + zeros, barWidth * 0.75, canvas.height - 20); ctx.fillText('1s: ' + ones, barWidth * 1.75, canvas.height - 20); ctx.fillText('Bit Distribution', canvas.width / 2, 15); }, // Additional stub functions for the enhanced QRNG visualization createQualityRadarChart: function(output) { // Placeholder for quality radar chart console.log('Quality radar chart would be implemented here'); }, updateQRNGStatisticalTests: function(output) { const container = document.getElementById('qrng-statistical-tests'); if (!container) return; if (!output.statistics || output.statistics.error) { container.innerHTML = '
Insufficient data for statistical analysis
'; return; } const stats = output.statistics; container.innerHTML = `
Quality Score: ${Math.round(stats.quality_score)}/100
Entropy: ${(stats.entropy_percentage || 0).toFixed(1)}%
Bias: ${((stats.bias || 0) * 100).toFixed(2)}%
`; }, updateQRNGBitDetails: function(output) { const container = document.getElementById('qrng-bit-details'); if (!container) return; // Determine configuration type for better user understanding let configType = 'Educational'; let configColor = 'primary'; let configIcon = 'graduation-cap'; if (output.post_processing_enabled && output.noise_level > 0.05) { configType = 'Cryptographic'; configColor = 'success'; configIcon = 'lock'; } else if (output.noise_level > 0 || output.hardware_simulation) { configType = 'Research/Advanced'; configColor = 'warning'; configIcon = 'cogs'; } container.innerHTML = `
Configuration: ${configType}
Bits Generated: ${output.num_bits}
Source: ${output.source_name || 'Unknown'}
Noise Level: ${(output.noise_level * 100).toFixed(1)}%
Post-Processing: ${output.post_processing_enabled ? '✓ Enabled' : '✗ Disabled'}
Hardware Simulation: ${output.hardware_simulation ? '✓ Enabled' : '✗ Disabled'}
Generation Time: ${output.generation_time_ms ? output.generation_time_ms.toFixed(1) + 'ms' : 'N/A'}
Feature Guide
${output.post_processing_enabled ? '
Bias Correction: Applied von Neumann extraction for cryptographic quality
' : '
Raw Output: Pure quantum measurements without processing
' } ${output.noise_level > 0 ? `
Realistic Noise: Simulating ${(output.noise_level * 100).toFixed(1)}% hardware imperfections
` : '
Ideal Simulation: Perfect quantum operations
' } ${output.hardware_simulation ? '
Hardware Timing: Realistic delays included
' : '
Instant Mode: No hardware delays
' }
`; }, updateQRNGApplications: function(output) { // Generate applications from the random number const cryptoKey = output.random_number.toString(16).padStart(8, '0').toUpperCase(); const diceRoll = (output.random_number % 6) + 1; const uuid = `${cryptoKey}-4000-8000-${cryptoKey}`; const cryptoEl = document.getElementById('qrng-crypto-key'); const diceEl = document.getElementById('qrng-dice-result'); const uuidEl = document.getElementById('qrng-uuid'); if (cryptoEl) cryptoEl.value = cryptoKey; if (diceEl) diceEl.textContent = diceRoll; if (uuidEl) uuidEl.value = uuid; }, updateQRNGEducationalContent: function(output) { const container = document.getElementById('qrng-educational-content'); if (!container) return; container.innerHTML = `
Quantum Random Number Generation

This simulation demonstrates how quantum mechanics provides true randomness through:

Source Used: ${output.source_description || 'Quantum superposition'}
`; }, addToQRNGHistory: function(output) { if (!window.qrngHistory) { window.qrngHistory = []; } window.qrngHistory.unshift({ timestamp: output.timestamp || new Date().toLocaleTimeString(), number: output.random_number, binary: output.bits_string, source: output.source_name, quality: output.statistics && !output.statistics.error ? Math.round(output.statistics.quality_score) : 0 }); // Keep only last 20 entries if (window.qrngHistory.length > 20) { window.qrngHistory = window.qrngHistory.slice(0, 20); } this.updateQRNGHistoryDisplay(); }, updateQRNGHistoryDisplay: function() { const container = document.getElementById('qrng-history-container'); if (!container || !window.qrngHistory) return; if (window.qrngHistory.length === 0) { container.innerHTML = '
No generation history available
'; return; } let html = '
'; window.qrngHistory.slice(0, 10).forEach(entry => { html += ``; }); html += '
TimeNumberBinarySourceQuality
${entry.timestamp} ${entry.number} ${entry.binary} ${entry.source} ${entry.quality}
'; container.innerHTML = html; }, setupQRNGControls: function(output) { // Setup export functionality const exportBtn = document.getElementById('qrng-export-btn'); if (exportBtn) { exportBtn.onclick = () => { const data = `Random Number: ${output.random_number}\nBinary: ${output.bits_string}\nSource: ${output.source_name}`; const blob = new Blob([data], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'qrng_data.txt'; a.click(); URL.revokeObjectURL(url); }; } } }; // End of QuantumVisualizer object