import React, { useState, useEffect, useRef } from 'react';
export default function FeynmanPathIntegralSimulator() {
// State for all simulations
const [numPaths, setNumPaths] = useState(20);
const [timeEvolution, setTimeEvolution] = useState(0);
const [measurementStrength, setMeasurementStrength] = useState(0.5);
const [numDiagnostics, setNumDiagnostics] = useState(5);
const [isAnimating, setIsAnimating] = useState(true);
const [showPhases, setShowPhases] = useState(true);
// Canvas refs
const pathCanvasRef = useRef(null);
const phaseCanvasRef = useRef(null);
const measurementCanvasRef = useRef(null);
// Animation loop
useEffect(() => {
if (!isAnimating) return;
const interval = setInterval(() => {
setTimeEvolution(t => (t + 0.05) % (2 * Math.PI));
}, 50);
return () => clearInterval(interval);
}, [isAnimating]);
// Draw path integral visualization
useEffect(() => {
const canvas = pathCanvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
// Clear
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, width, height);
// Draw all possible paths
const startX = 50;
const endX = width - 50;
const startY = height / 2;
// Calculate amplitudes for each path
const paths = [];
for (let i = 0; i < numPaths; i++) {
const pathIndex = i - numPaths / 2;
const amplitude = Math.exp(-0.1 * pathIndex * pathIndex); // Gaussian
const phase = pathIndex * 0.5 + timeEvolution;
paths.push({ amplitude, phase, pathIndex });
}
// Draw paths
paths.forEach(({ amplitude, phase, pathIndex }) => {
const alpha = amplitude * 0.5;
const color = `rgba(0, 255, 100, ${alpha})`;
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(startX, startY);
// Draw wavy path
for (let x = startX; x <= endX; x += 5) {
const progress = (x - startX) / (endX - startX);
const yOffset = pathIndex * 30 * Math.sin(progress * Math.PI * 4 + phase);
ctx.lineTo(x, startY + yOffset);
}
ctx.stroke();
// Draw phase arrow at end if enabled
if (showPhases) {
const endY = startY + pathIndex * 30 * Math.sin(Math.PI * 4 + phase);
const arrowLength = amplitude * 30;
const arrowX = endX + arrowLength * Math.cos(phase);
const arrowY = endY + arrowLength * Math.sin(phase);
ctx.strokeStyle = `rgba(255, 255, 0, ${amplitude})`;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(endX, endY);
ctx.lineTo(arrowX, arrowY);
ctx.stroke();
// Arrow head
ctx.fillStyle = `rgba(255, 255, 0, ${amplitude})`;
ctx.beginPath();
ctx.arc(arrowX, arrowY, 4, 0, Math.PI * 2);
ctx.fill();
}
});
// Calculate total amplitude (sum of all contributions)
let totalReal = 0;
let totalImag = 0;
paths.forEach(({ amplitude, phase }) => {
totalReal += amplitude * Math.cos(phase);
totalImag += amplitude * Math.sin(phase);
});
const totalAmplitude = Math.sqrt(totalReal * totalReal + totalImag * totalImag);
const totalPhase = Math.atan2(totalImag, totalReal);
// Draw total amplitude arrow
const centerX = width / 2;
const centerY = height - 80;
const totalArrowLength = totalAmplitude * 50;
const totalArrowX = centerX + totalArrowLength * Math.cos(totalPhase);
const totalArrowY = centerY + totalArrowLength * Math.sin(totalPhase);
ctx.strokeStyle = '#00ffff';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(totalArrowX, totalArrowY);
ctx.stroke();
ctx.fillStyle = '#00ffff';
ctx.beginPath();
ctx.arc(totalArrowX, totalArrowY, 6, 0, Math.PI * 2);
ctx.fill();
// Labels
ctx.fillStyle = '#00ff00';
ctx.font = '14px monospace';
ctx.fillText('All possible paths', 10, 30);
ctx.fillStyle = '#ffff00';
ctx.fillText('Phase arrows', 10, 50);
ctx.fillStyle = '#00ffff';
ctx.fillText(`Total amplitude: ${totalAmplitude.toFixed(2)}`, centerX - 80, height - 20);
}, [numPaths, timeEvolution, showPhases]);
// Draw phase space diagram
useEffect(() => {
const canvas = phaseCanvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, width, height);
// Draw complex plane
const centerX = width / 2;
const centerY = height / 2;
const scale = 80;
// Axes
ctx.strokeStyle = '#333';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, centerY);
ctx.lineTo(width, centerY);
ctx.moveTo(centerX, 0);
ctx.lineTo(centerX, height);
ctx.stroke();
// Draw unit circle
ctx.strokeStyle = 'rgba(100, 100, 100, 0.3)';
ctx.beginPath();
ctx.arc(centerX, centerY, scale, 0, Math.PI * 2);
ctx.stroke();
// Draw all path contributions
const paths = [];
for (let i = 0; i < numPaths; i++) {
const pathIndex = i - numPaths / 2;
const amplitude = Math.exp(-0.1 * pathIndex * pathIndex);
const phase = pathIndex * 0.5 + timeEvolution;
const x = centerX + amplitude * scale * Math.cos(phase);
const y = centerY + amplitude * scale * Math.sin(phase);
// Draw vector
ctx.strokeStyle = `rgba(0, 255, 100, ${amplitude * 0.5})`;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(x, y);
ctx.stroke();
// Draw point
ctx.fillStyle = `rgba(0, 255, 100, ${amplitude})`;
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2);
ctx.fill();
paths.push({ amplitude, phase });
}
// Calculate and draw sum
let sumReal = 0;
let sumImag = 0;
paths.forEach(({ amplitude, phase }) => {
sumReal += amplitude * Math.cos(phase);
sumImag += amplitude * Math.sin(phase);
});
const sumX = centerX + sumReal * scale;
const sumY = centerY + sumImag * scale;
ctx.strokeStyle = '#00ffff';
ctx.lineWidth = 4;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(sumX, sumY);
ctx.stroke();
ctx.fillStyle = '#00ffff';
ctx.beginPath();
ctx.arc(sumX, sumY, 6, 0, Math.PI * 2);
ctx.fill();
// Labels
ctx.fillStyle = '#00ff00';
ctx.font = '12px monospace';
ctx.fillText('Re', width - 30, centerY - 10);
ctx.fillText('Im', centerX + 10, 20);
ctx.fillStyle = '#00ffff';
ctx.fillText('Σ(paths)', sumX + 10, sumY - 10);
}, [numPaths, timeEvolution]);
// Draw measurement effect
useEffect(() => {
const canvas = measurementCanvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
const width = canvas.width;
const height = canvas.height;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, width, height);
const centerY = height / 2;
// Natural sigma
const sigma0 = 0.5; // mm
const alpha = 0.1; // mm^2 per diagnostic
const effectiveSigma = Math.sqrt(sigma0 * sigma0 + alpha * numDiagnostics);
// Draw probability distribution (natural)
ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)';
ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
ctx.lineWidth = 2;
ctx.beginPath();
for (let x = 0; x < width; x++) {
const position = (x - width / 2) / 100; // Convert to mm
const prob = Math.exp(-position * position / (2 * sigma0 * sigma0));
const y = centerY - prob * 150;
if (x === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
ctx.lineTo(width, centerY);
ctx.lineTo(0, centerY);
ctx.closePath();
ctx.fill();
ctx.stroke();
// Draw probability distribution (with measurements)
ctx.strokeStyle = 'rgba(255, 255, 0, 0.8)';
ctx.fillStyle = 'rgba(255, 255, 0, 0.1)';
ctx.lineWidth = 2;
ctx.beginPath();
for (let x = 0; x < width; x++) {
const position = (x - width / 2) / 100;
const prob = Math.exp(-position * position / (2 * effectiveSigma * effectiveSigma));
const y = centerY - prob * 150;
if (x === 0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
ctx.lineTo(width, centerY);
ctx.lineTo(0, centerY);
ctx.closePath();
ctx.fill();
ctx.stroke();
// Draw measurement collapses
for (let i = 0; i < numDiagnostics; i++) {
const x = (i + 1) * width / (numDiagnostics + 1);
const measurementY = centerY + (Math.sin(timeEvolution * 2 + i) * measurementStrength * 100);
ctx.strokeStyle = 'rgba(0, 200, 255, 0.6)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(x, centerY);
ctx.lineTo(x, measurementY);
ctx.stroke();
ctx.fillStyle = 'rgba(0, 200, 255, 0.8)';
ctx.beginPath();
ctx.arc(x, measurementY, 5, 0, Math.PI * 2);
ctx.fill();
}
// Labels
ctx.fillStyle = '#ff0000';
ctx.font = '14px monospace';
ctx.fillText(`Natural σ = ${sigma0.toFixed(2)} mm`, 10, 30);
ctx.fillStyle = '#ffff00';
ctx.fillText(`Measured σ = ${effectiveSigma.toFixed(2)} mm`, 10, 50);
ctx.fillStyle = '#00ccff';
ctx.fillText(`N diagnostics = ${numDiagnostics}`, 10, 70);
// Draw equation
ctx.fillStyle = '#ffffff';
ctx.font = '16px monospace';
ctx.fillText(`σ² = ${sigma0}² + ${alpha}·N = ${(effectiveSigma * effectiveSigma).toFixed(2)}`,
width / 2 - 150, height - 20);
}, [numDiagnostics, measurementStrength, timeEvolution]);
return (
◊ᶠᴱʸᴺᴹᴬᴺ Path Integral Simulator
"The electron does something entirely reasonable - it goes every way at once!"
Interactive visualization of quantum path integrals and measurement back-action
{/* Control Panel */}
{/* Visualization 1: Path Integral */}
Path Integral: All Possible Paths
The particle explores EVERY path from start to end. Each path contributes
an amplitude (brightness) and phase (yellow arrow). Sum them all → total probability!
{/* Visualization 2: Phase Space */}
Complex Phase Space: Vector Addition
Each path = vector in complex plane. Green vectors = individual paths.
Cyan vector = total amplitude (sum of all). Watch them spin and interfere!
{/* Visualization 3: Measurement Effect */}
Measurement Back-Action: σ ∝ √N
Red = natural quantum spread (no measurements). Yellow = with measurements.
Blue spikes = each diagnostic collapse. More diagnostics → wider spread!
{/* Physics Explanation */}
The Physics (Feynman's Way)
Path Integrals:
Amplitude to go from A to B = Σ(all paths) exp(iS/ℏ)
Each path has action S. That makes phase rotate. Add all rotating
phases → interference → quantum mechanics!
Measurement Collapse:
Before measurement: |ψ⟩ = Σ cₙ|n⟩ (superposition)
After measurement: |ψ⟩ → |n_measured⟩ (collapse)
This collapse COSTS ENERGY. It perturbs the system. More measurements =
more perturbation = larger fluctuations!
Why σ ∝ √N:
σ² = σ₀² + α·N
Natural spread (σ₀) + measurement perturbation (α per diagnostic).
Each measurement adds variance → total variance grows linearly →
standard deviation grows as √N.
The Solution:
STOP MEASURING SO MUCH. Design the machine to be naturally stable.
Let the path integral find its own minimum without constant collapse.
{/* Footer */}
"What I cannot create, I do not understand."
— Richard Feynman
◊ᴹᴱᴹᴼᴿʸ⁻ᶜᴼᴹᴾᴸᴱᵀᴱ
);
}
Comments
Post a Comment