MophongLT / static /js /plugin_visualizations.js
gaialive's picture
Upload 170 files
227c43a verified
/**
* 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 = `
<p class="text-muted">
<i class="fas fa-info-circle me-1"></i>
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.
</p>
`;
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 = `
<h4 class="text-white mb-0">
<i class="fas ${authSuccess ? 'fa-check-circle' : 'fa-times-circle'} me-2"></i>
Authentication ${authSuccess ? 'Successful' : 'Failed'}
</h4>
`;
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 = `
<div class="card-header d-flex align-items-center">
<div class="step-number rounded-circle bg-primary text-white me-3">
${index + 1}
</div>
<h5 class="mb-0">
<i class="fas fa-${step.icon} me-2"></i>
${step.title}
</h5>
</div>
<div class="card-body">
<p class="step-description">${step.description}</p>
<div class="step-details text-muted small">
${step.details}
</div>
</div>
`;
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 = `
<h5 class="mb-3">Post-Quantum Security Advantage</h5>
<div class="row">
<div class="col-md-6">
<div class="card h-100 bg-danger bg-opacity-10">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-unlock me-2"></i>
Traditional Cryptography
</h5>
<p class="card-text">RSA and ECC rely on integer factorization and discrete logarithm problems that can be efficiently solved by quantum computers using Shor's algorithm.</p>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100 bg-success bg-opacity-10">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-lock me-2"></i>
Lattice-Based Cryptography
</h5>
<p class="card-text">Based on the hardness of solving lattice problems that remain difficult even for quantum computers, making it a foundation for post-quantum security.</p>
</div>
</div>
</div>
</div>
`;
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 = `
<h5><i class="fas fa-shield-alt me-2"></i>Security Strength Explanation</h5>
<p>
<strong>Quantum Security:</strong> 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.
</p>
<p class="mb-0">
<strong>NIST Standardization:</strong> Lattice-based cryptography forms the foundation of several NIST post-quantum
cryptography standards, acknowledging its robustness against both classical and quantum attacks.
</p>
`;
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 = '<div class="alert alert-warning">Failed to initialize chart</div>';
}
},
// 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 = '<div class="alert alert-warning">Failed to initialize visualization</div>';
}
},
// 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 = `
<div class="alert alert-danger mb-0">
<strong>QBER: ${(qber * 100).toFixed(2)}%</strong> - Above security threshold (${(securityThreshold * 100).toFixed(2)}%)
<br>Possible eavesdropping detected!
</div>
`;
} else {
interpretation.innerHTML = `
<div class="alert alert-success mb-0">
<strong>QBER: ${(qber * 100).toFixed(2)}%</strong> - Below security threshold (${(securityThreshold * 100).toFixed(2)}%)
<br>No evidence of eavesdropping
</div>
`;
}
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 = '<i class="fas fa-user-secret me-2"></i> 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 = `
<strong>Attack Strategy:</strong> ${data.eve_strategy || 'intercept_resend'}
<div class="progress mt-1">
<div class="progress-bar bg-info" role="progressbar" style="width: 100%"></div>
</div>
`;
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 = `
<strong>Information Leakage:</strong> ${(leakageRatio * 100).toFixed(1)}%
<div class="progress mt-1">
<div class="progress-bar bg-warning" role="progressbar"
style="width: ${leakageRatio * 100}%"></div>
</div>
`;
eveMetrics.appendChild(leakage);
// Add detection probability
const detection = document.createElement('div');
detection.className = 'mb-3';
const detectionProb = eveResults.detection_probability || 0;
detection.innerHTML = `
<strong>Detection Probability:</strong> ${(detectionProb * 100).toFixed(1)}%
<div class="progress mt-1">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${detectionProb * 100}%"></div>
</div>
`;
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
? '<i class="fas fa-check-circle me-2"></i> Eavesdropper detected!'
: '<i class="fas fa-exclamation-triangle me-2"></i> 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 = `
<div class="step-header">
<span class="badge bg-primary me-2">1</span>
<strong>Quantum Transmission</strong>
<span class="ms-auto">${Math.round(transmissionEfficiency * 100)}% efficiency</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-primary" role="progressbar"
style="width: ${transmissionEfficiency * 100}%"
aria-valuenow="${transmissionEfficiency * 100}" aria-valuemin="0" aria-valuemax="100">
${Math.round(rawKeyLength * transmissionEfficiency)} qubits received
</div>
</div>
<div class="step-footer small text-muted mt-1">
Raw qubits: ${rawKeyLength}${Math.round(rawKeyLength * transmissionEfficiency)} received
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-success me-2">2</span>
<strong>Basis Reconciliation</strong>
<span class="ms-auto">${Math.round(siftedRatio * 100)}% retention</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${siftedRatio * 100}%"
aria-valuenow="${siftedRatio * 100}" aria-valuemin="0" aria-valuemax="100">
${siftedKeyLength} matching bases
</div>
</div>
<div class="step-footer small text-muted mt-1">
Sifted key: ${siftedKeyLength} bits (bases matched ${Math.round(siftedRatio * 100)}% of the time)
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-info me-2">3</span>
<strong>Information Reconciliation</strong>
<span class="ms-auto">${Math.round(reconciliationRatio * 100)}% retention</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-info" role="progressbar"
style="width: ${reconciliationRatio * 100}%"
aria-valuenow="${reconciliationRatio * 100}" aria-valuemin="0" aria-valuemax="100">
${siftedKeyLength - bitsUsed} bits
</div>
</div>
<div class="step-footer small text-muted mt-1">
Error correction: ${correctedBits} errors fixed using ${bitsUsed} bits
<br>Remaining error rate: ${(remainingErrors * 100).toFixed(4)}%
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-warning me-2">4</span>
<strong>Privacy Amplification</strong>
<span class="ms-auto">${Math.round(finalRatio * 100)}% retention</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-warning" role="progressbar"
style="width: ${finalRatio * 100}%"
aria-valuenow="${finalRatio * 100}" aria-valuemin="0" aria-valuemax="100">
${finalKeyLength} bits
</div>
</div>
<div class="step-footer small text-muted mt-1">
Final secure key: ${finalKeyLength} bits (${(finalKeyLength / rawKeyLength * 100).toFixed(1)}% of raw qubits)
</div>
`;
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 = `
<td>Photon Loss</td>
<td>${(noiseModel.photon_loss * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-danger" role="progressbar"
style="width: ${noiseModel.photon_loss * 100}%"></div>
</div>
</td>
`;
tbody.appendChild(photonLossRow);
// Add polarization drift row
const polarizationRow = document.createElement('tr');
polarizationRow.innerHTML = `
<td>Polarization Drift</td>
<td>${(noiseModel.polarization_drift * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-warning" role="progressbar"
style="width: ${Math.min(100, noiseModel.polarization_drift * 1000)}%"></div>
</div>
</td>
`;
tbody.appendChild(polarizationRow);
// Add phase drift row
const phaseRow = document.createElement('tr');
phaseRow.innerHTML = `
<td>Phase Drift</td>
<td>${(noiseModel.phase_drift * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-info" role="progressbar"
style="width: ${Math.min(100, noiseModel.phase_drift * 1000)}%"></div>
</div>
</td>
`;
tbody.appendChild(phaseRow);
// Add detector efficiency row
const detectorRow = document.createElement('tr');
detectorRow.innerHTML = `
<td>Detector Efficiency</td>
<td>${(noiseModel.detector_efficiency * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${noiseModel.detector_efficiency * 100}%"></div>
</div>
</td>
`;
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 = `
<strong>Theoretical Secure Key Rate:</strong> ${secureKeyRate.toFixed(2)} bits/second
<div class="progress mt-2">
<div class="progress-bar bg-primary" role="progressbar"
style="width: ${Math.min(100, secureKeyRate / 1000 * 100)}%"></div>
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-primary me-2">1</span>
<strong>Quantum Transmission</strong>
<span class="ms-auto">${Math.round(transmissionEfficiency * 100)}% efficiency</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-primary" role="progressbar"
style="width: ${transmissionEfficiency * 100}%"
aria-valuenow="${transmissionEfficiency * 100}" aria-valuemin="0" aria-valuemax="100">
${Math.round(rawKeyLength * transmissionEfficiency)} qubits received
</div>
</div>
<div class="step-footer small text-muted mt-1">
Raw qubits: ${rawKeyLength}${Math.round(rawKeyLength * transmissionEfficiency)} received
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-success me-2">2</span>
<strong>Basis Reconciliation</strong>
<span class="ms-auto">${Math.round(siftedRatio * 100)}% retention</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${siftedRatio * 100}%"
aria-valuenow="${siftedRatio * 100}" aria-valuemin="0" aria-valuemax="100">
${siftedKeyLength} matching bases
</div>
</div>
<div class="step-footer small text-muted mt-1">
Sifted key: ${siftedKeyLength} bits (bases matched ${Math.round(siftedRatio * 100)}% of the time)
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-info me-2">3</span>
<strong>Information Reconciliation</strong>
<span class="ms-auto">${Math.round(reconciliationRatio * 100)}% retention</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-info" role="progressbar"
style="width: ${reconciliationRatio * 100}%"
aria-valuenow="${reconciliationRatio * 100}" aria-valuemin="0" aria-valuemax="100">
${siftedKeyLength - bitsUsed} bits
</div>
</div>
<div class="step-footer small text-muted mt-1">
Error correction: ${correctedBits} errors fixed using ${bitsUsed} bits
<br>Remaining error rate: ${(remainingErrors * 100).toFixed(4)}%
</div>
`;
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 = `
<div class="step-header">
<span class="badge bg-warning me-2">4</span>
<strong>Privacy Amplification</strong>
<span class="ms-auto">${Math.round(finalRatio * 100)}% retention</span>
</div>
<div class="progress mt-2">
<div class="progress-bar bg-warning" role="progressbar"
style="width: ${finalRatio * 100}%"
aria-valuenow="${finalRatio * 100}" aria-valuemin="0" aria-valuemax="100">
${finalKeyLength} bits
</div>
</div>
<div class="step-footer small text-muted mt-1">
Final secure key: ${finalKeyLength} bits (${(finalKeyLength / rawKeyLength * 100).toFixed(1)}% of raw qubits)
</div>
`;
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 = `
<td>Photon Loss</td>
<td>${(noiseModel.photon_loss * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-danger" role="progressbar"
style="width: ${noiseModel.photon_loss * 100}%"></div>
</div>
</td>
`;
tbody.appendChild(photonLossRow);
// Add polarization drift row
const polarizationRow = document.createElement('tr');
polarizationRow.innerHTML = `
<td>Polarization Drift</td>
<td>${(noiseModel.polarization_drift * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-warning" role="progressbar"
style="width: ${Math.min(100, noiseModel.polarization_drift * 1000)}%"></div>
</div>
</td>
`;
tbody.appendChild(polarizationRow);
// Add phase drift row
const phaseRow = document.createElement('tr');
phaseRow.innerHTML = `
<td>Phase Drift</td>
<td>${(noiseModel.phase_drift * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-info" role="progressbar"
style="width: ${Math.min(100, noiseModel.phase_drift * 1000)}%"></div>
</div>
</td>
`;
tbody.appendChild(phaseRow);
// Add detector efficiency row
const detectorRow = document.createElement('tr');
detectorRow.innerHTML = `
<td>Detector Efficiency</td>
<td>${(noiseModel.detector_efficiency * 100).toFixed(2)}%</td>
<td>
<div class="progress">
<div class="progress-bar bg-success" role="progressbar"
style="width: ${noiseModel.detector_efficiency * 100}%"></div>
</div>
</td>
`;
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 = `
<strong>Theoretical Secure Key Rate:</strong> ${secureKeyRate.toFixed(2)} bits/second
<div class="progress mt-2">
<div class="progress-bar bg-primary" role="progressbar"
style="width: ${Math.min(100, secureKeyRate / 1000 * 100)}%"></div>
</div>
`;
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 = '<div class="alert alert-warning">Failed to initialize chart</div>';
}
},
// 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 = '<div class="alert alert-warning">Failed to initialize visualization</div>';
}
},
// 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 = '<div class="alert alert-warning">Failed to initialize visualization</div>';
}
},
// 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 = '<div class="alert alert-warning">Failed to initialize visualization</div>';
}
},
// 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 = '<div class="alert alert-warning">Failed to initialize visualization</div>';
}
},
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 = '<div class="alert alert-warning">Chart.js library not available</div>';
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 = '<div class="alert alert-warning">Failed to initialize chart</div>';
}
},
// 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 = '<div class="alert alert-warning">Failed to initialize visualization</div>';
}
},
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 = `
<div class="row">
<!-- Main Statistics Dashboard -->
<div class="col-md-8">
<div class="card mb-4">
<div class="card-header bg-gradient-primary text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0"><i class="fas fa-chart-line me-2"></i>Quantum Randomness Dashboard</h5>
<div class="badge bg-light text-dark" id="qrng-quality-badge">Quality: --</div>
</div>
<div class="card-body">
<!-- Key Metrics Row -->
<div class="row mb-4">
<div class="col-md-3">
<div class="text-center p-3 border rounded bg-light">
<h3 class="text-primary mb-1" id="qrng-random-number">--</h3>
<small class="text-muted">Random Number</small>
</div>
</div>
<div class="col-md-3">
<div class="text-center p-3 border rounded bg-light">
<h3 class="text-success mb-1" id="qrng-entropy">--</h3>
<small class="text-muted">Entropy %</small>
</div>
</div>
<div class="col-md-3">
<div class="text-center p-3 border rounded bg-light">
<h3 class="text-info mb-1" id="qrng-bias">--</h3>
<small class="text-muted">Bias</small>
</div>
</div>
<div class="col-md-3">
<div class="text-center p-3 border rounded bg-light">
<h3 class="text-warning mb-1" id="qrng-performance">--</h3>
<small class="text-muted">Bits/sec</small>
</div>
</div>
</div>
<!-- Bit Visualization -->
<div class="mb-4">
<h6><i class="fas fa-binary me-2"></i>Bit Sequence Visualization</h6>
<div id="qrng-bit-sequence" class="p-3 bg-dark text-white rounded font-monospace" style="overflow-x: auto; white-space: nowrap;"></div>
</div>
<!-- Statistical Charts -->
<div class="row">
<div class="col-md-6">
<canvas id="qrng-distribution-chart" width="300" height="200"></canvas>
</div>
<div class="col-md-6">
<canvas id="qrng-quality-radar" width="300" height="200"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Control Panel & Information -->
<div class="col-md-4">
<!-- Source Information -->
<div class="card mb-3">
<div class="card-header bg-info text-white">
<h6 class="mb-0"><i class="fas fa-atom me-2"></i>Quantum Source</h6>
</div>
<div class="card-body">
<div id="qrng-source-info">
<h6 id="qrng-source-name" class="text-primary">--</h6>
<p id="qrng-source-description" class="small text-muted">--</p>
<div class="progress mb-2" style="height: 5px;">
<div id="qrng-noise-indicator" class="progress-bar bg-warning" style="width: 0%"></div>
</div>
<small class="text-muted">Noise Level: <span id="qrng-noise-level">0%</span></small>
</div>
</div>
</div>
<!-- Real-time Controls -->
<div class="card mb-3">
<div class="card-header bg-secondary text-white">
<h6 class="mb-0"><i class="fas fa-sliders-h me-2"></i>Interactive Controls</h6>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label small">Export Format:</label>
<select id="qrng-export-format" class="form-select form-select-sm">
<option value="binary">Binary</option>
<option value="hex">Hexadecimal</option>
<option value="base64">Base64</option>
<option value="csv">CSV</option>
</select>
</div>
<div class="d-grid gap-2">
<button id="qrng-export-btn" class="btn btn-outline-primary btn-sm">
<i class="fas fa-download me-1"></i>Export Data
</button>
<button id="qrng-regenerate-btn" class="btn btn-outline-success btn-sm">
<i class="fas fa-refresh me-1"></i>Generate New
</button>
</div>
</div>
</div>
<!-- Applications Demo -->
<div class="card">
<div class="card-header bg-success text-white">
<h6 class="mb-0"><i class="fas fa-lightbulb me-2"></i>Applications</h6>
</div>
<div class="card-body">
<div id="qrng-applications">
<div class="mb-3">
<label class="small fw-bold">Cryptographic Key:</label>
<div class="input-group input-group-sm">
<input id="qrng-crypto-key" class="form-control font-monospace" readonly>
<button class="btn btn-outline-secondary" onclick="this.previousElementSibling.select(); document.execCommand('copy');">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="mb-3">
<label class="small fw-bold">Dice Roll (1-6):</label>
<div class="text-center">
<span id="qrng-dice-result" class="badge bg-primary fs-6">-</span>
</div>
</div>
<div>
<label class="small fw-bold">UUID:</label>
<div class="input-group input-group-sm">
<input id="qrng-uuid" class="form-control font-monospace" readonly>
<button class="btn btn-outline-secondary" onclick="this.previousElementSibling.select(); document.execCommand('copy');">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Detailed Analysis Tabs -->
<div class="card mt-4">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<button class="nav-link active" id="qrng-tab-stats" data-bs-toggle="tab" data-bs-target="#qrng-stats-content">
<i class="fas fa-chart-bar me-1"></i>Statistical Tests
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="qrng-tab-bits" data-bs-toggle="tab" data-bs-target="#qrng-bits-content">
<i class="fas fa-microchip me-1"></i>Bit Analysis
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="qrng-tab-history" data-bs-toggle="tab" data-bs-target="#qrng-history-content">
<i class="fas fa-history me-1"></i>Generation History
</button>
</li>
<li class="nav-item">
<button class="nav-link" id="qrng-tab-education" data-bs-toggle="tab" data-bs-target="#qrng-education-content">
<i class="fas fa-graduation-cap me-1"></i>Learn More
</button>
</li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<div class="tab-pane fade show active" id="qrng-stats-content">
<div id="qrng-statistical-tests"></div>
</div>
<div class="tab-pane fade" id="qrng-bits-content">
<div id="qrng-bit-details"></div>
</div>
<div class="tab-pane fade" id="qrng-history-content">
<div id="qrng-history-container"></div>
</div>
<div class="tab-pane fade" id="qrng-education-content">
<div id="qrng-educational-content"></div>
</div>
</div>
</div>
</div>
`;
}
// 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 += `<span class="badge ${bgClass} ${textClass} me-1 mb-1" style="font-size: 0.9em;"
title="Bit ${i}: ${bit}">${bit}</span>`;
}
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 = '<div class="alert alert-info">Insufficient data for statistical analysis</div>';
return;
}
const stats = output.statistics;
container.innerHTML = `
<div class="alert alert-success">
<strong>Quality Score:</strong> ${Math.round(stats.quality_score)}/100<br>
<strong>Entropy:</strong> ${(stats.entropy_percentage || 0).toFixed(1)}%<br>
<strong>Bias:</strong> ${((stats.bias || 0) * 100).toFixed(2)}%
</div>
`;
},
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 = `
<div class="row">
<div class="col-md-8">
<div class="alert alert-${configColor}">
<h6><i class="fas fa-${configIcon} me-2"></i>Configuration: ${configType}</h6>
<div class="row">
<div class="col-md-6">
<strong>Bits Generated:</strong> ${output.num_bits}<br>
<strong>Source:</strong> ${output.source_name || 'Unknown'}<br>
<strong>Noise Level:</strong> ${(output.noise_level * 100).toFixed(1)}%
</div>
<div class="col-md-6">
<strong>Post-Processing:</strong> ${output.post_processing_enabled ? '✓ Enabled' : '✗ Disabled'}<br>
<strong>Hardware Simulation:</strong> ${output.hardware_simulation ? '✓ Enabled' : '✗ Disabled'}<br>
<strong>Generation Time:</strong> ${output.generation_time_ms ? output.generation_time_ms.toFixed(1) + 'ms' : 'N/A'}
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h6 class="mb-0">Feature Guide</h6>
</div>
<div class="card-body">
<small>
${output.post_processing_enabled ?
'<div class="text-success mb-2"><i class="fas fa-check me-1"></i><strong>Bias Correction:</strong> Applied von Neumann extraction for cryptographic quality</div>' :
'<div class="text-muted mb-2"><i class="fas fa-info me-1"></i><strong>Raw Output:</strong> Pure quantum measurements without processing</div>'
}
${output.noise_level > 0 ?
`<div class="text-warning mb-2"><i class="fas fa-exclamation-triangle me-1"></i><strong>Realistic Noise:</strong> Simulating ${(output.noise_level * 100).toFixed(1)}% hardware imperfections</div>` :
'<div class="text-info mb-2"><i class="fas fa-star me-1"></i><strong>Ideal Simulation:</strong> Perfect quantum operations</div>'
}
${output.hardware_simulation ?
'<div class="text-primary"><i class="fas fa-clock me-1"></i><strong>Hardware Timing:</strong> Realistic delays included</div>' :
'<div class="text-muted"><i class="fas fa-zap me-1"></i><strong>Instant Mode:</strong> No hardware delays</div>'
}
</small>
</div>
</div>
</div>
</div>
`;
},
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 = `
<div class="row">
<div class="col-md-12">
<h5>Quantum Random Number Generation</h5>
<p>This simulation demonstrates how quantum mechanics provides true randomness through:</p>
<ul>
<li><strong>Superposition:</strong> ${output.quantum_principles?.superposition || 'Quantum states existing in multiple possibilities simultaneously'}</li>
<li><strong>Measurement:</strong> ${output.quantum_principles?.measurement || 'Random collapse upon observation'}</li>
<li><strong>Uncertainty:</strong> ${output.quantum_principles?.uncertainty || 'Fundamental unpredictability'}</li>
</ul>
<div class="alert alert-primary">
<strong>Source Used:</strong> ${output.source_description || 'Quantum superposition'}
</div>
</div>
</div>
`;
},
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 = '<div class="alert alert-info">No generation history available</div>';
return;
}
let html = '<div class="table-responsive"><table class="table table-sm"><thead><tr><th>Time</th><th>Number</th><th>Binary</th><th>Source</th><th>Quality</th></tr></thead><tbody>';
window.qrngHistory.slice(0, 10).forEach(entry => {
html += `<tr>
<td><small>${entry.timestamp}</small></td>
<td><code>${entry.number}</code></td>
<td><code class="small">${entry.binary}</code></td>
<td><small>${entry.source}</small></td>
<td><span class="badge ${entry.quality >= 80 ? 'bg-success' : entry.quality >= 60 ? 'bg-warning' : 'bg-danger'}">${entry.quality}</span></td>
</tr>`;
});
html += '</tbody></table></div>';
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