Quantum
Quest

Algorithms, Math, and Physics

Simulating the EPR experiment using Python and OpenGL

Following my blog post on Bell’s theorem and the EPR paper here, I wrote a program to simulate the Einstein-Podolsky-Rosen (EPR) experiment, a cornerstone of quantum mechanics. Utilizing the PyQt6 framework and OpenGL, my program visualizes the entangled spin states of two particles and demonstrates the violation of Bell’s theorem, underscoring the non-locality of quantum mechanics.

Overview

The EPR experiment, proposed by Einstein, Podolsky, and Rosen in 1935, explores the peculiarities of quantum entanglement. It challenges the completeness of quantum mechanics by suggesting that particles can influence each other instantaneously over any distance, a phenomenon Einstein famously referred to as “spooky action at a distance.”

To explore this, I developed a Python application that simulates the measurement of entangled spin states. The program is written using the PyQt6 framework for the GUI and OpenGL for the graphical representation of the apparatus and measurements.

Key features of the program

  • Simulation Types: The program allows simulation of different quantum states: singlet state, and three triplet states.
  • Customizable Parameters: Users can set the number of measurements, colors for spin-up and spin-down results, and the angles of measurement for both apparatus.
  • Graphical Visualization: The OpenGL visualization includes apparatus representation, measurement results, and spin directions.

Mathematical foundations

The program simulates an experimental apparatus designed to study quantum entanglement and spin states in a system similar to the EPR (Einstein-Podolsky-Rosen) experiment. A source emits pairs of spin-½ particles in a singlet state, with each particle traveling toward a separate detector. The singlet state wavefunction is given by:

\psi = \frac{1}{\sqrt{2}} (| ud \rangle - | du \rangle)

Each detector in this setup simulate a Stern-Gerlach magnet, oriented along one of three possible directions, each separated by 120°. These magnets deflect the particles based on their spin states—either up (northward) or down (southward). The deflection direction correlates with the particle’s spin state, where spin up and spin down are detected as distinct outcomes.

The experimental apparatus features a button to select the orientation of the Stern-Gerlach magnets. The detection mechanism is color-coded: the first detector flashes one color (green by default) for spin up and another (red by default) for spin down, while the second detector uses the reversed color scheme - red the sfor spin up and green for spin down. This ensures that correlated pairs, as predicted by the singlet state, will display opposite color indications at the detectors. A simultaneous red-red or green-green outcome confirms the anti-correlation property of the singlet state, aligning with quantum mechanical predictions.

Spin measurement

Here is a snippet of the code used to perform the measurement of the spin states:


def measureSpin(self, directions1: np.ndarray, directions2: np.ndarray, simulate_1: bool):
    def Rho1(psi: np.ndarray):
        return np.outer(psi, psi.conj()).reshape((2, 2, 2, 2)).trace(axis1=1, axis2=3)

    def Rho2(psi: np.ndarray):
        return np.outer(psi, psi.conj()).reshape((2, 2, 2, 2)).trace(axis1=0, axis2=2)

    psi = self.current_state
    projectorA_p1 = np.outer(directions1[0], directions1[0].conj())
    projectorA_m1 = np.outer(directions1[1], directions1[1].conj())
    projectorB_p1 = np.outer(directions2[0], directions2[0].conj())
    projectorB_m1 = np.outer(directions2[1], directions2[1].conj())

    if simulate_1:
        projector_p1_s = np.kron(projectorA_p1, np.eye(2))
        projector_m1_s = np.kron(projectorA_m1, np.eye(2))
        rho_i = Rho1(psi)
    else:
        projector_p1_s = np.kron(np.eye(2), projectorB_p1)
        projector_m1_s = np.kron(np.eye(2), projectorB_m1)
        rho_i = Rho2(psi)

    prob_p11 = np.linalg.norm(np.trace(np.dot(projector_p1_s, rho_i)))
    random_number1 = random.uniform(0, 1)
    sp1 = 1 if random_number1 < prob_p11 else -1
    psi_r = np.dot(projector_p1_s, psi) if sp1 == 1 else np.dot(projector_m1_s, psi)
    psi_r = psi_r / np.linalg.norm(psi_r)
    rho_j = Rho2(psi_r) if simulate_1 else Rho1(psi_r)
    prob_p12 = np.linalg.norm(np.trace(np.dot(projectorB_p1, rho_j)))
    random_number2 = random.uniform(0, 1)
    sp2 = 1 if random_number2 < prob_p12 else -1
    return (sp1, sp2)

The core of the program is the computation of the spin states of two entangled particles based on quantum mechanical principles. The function measureSpin takes in the directions for the measurement apparatus for two spins and simulates the process of measuring their spin states.

Density matrix definition

The density matrix, \rho, represents the state of a quantum system. It’s particularly useful for describing mixed states and obtaining probabilities of measurement outcomes. Here, two functions Rho1 and Rho2 calculate the reduced density matrices for the first and second spins, respectively, by tracing out the degrees of freedom of the other spin.

Projector operators

Projector operators are used to determine the probability of measuring a particular spin state. For a given direction \vec{n}, the projector for spin-up (|+1>) is defined as:

P_+ = |\vec{n}\rangle \langle \vec{n}|

Similarly, the projector for spin-down (|-1>) is:

P_- = |\vec{n}\rangle \langle \vec{n}|

In the code, these projectors are created using the directions provided.

Measurement simulation

If simulate_1 is true, the function simulates the measurement of the first spin. Otherwise, it simulates the second spin.
The projectors are used to calculate the probability of measuring spin-up for the first spin:

P(\text{spin 1} = +1) = \text{Tr}(P_+ \rho_1)

A random number is generated to simulate the measurement outcome based on this probability. If the random number is less than the calculated probability, the spin is measured as +1; otherwise, it is -1.

Wavefunction collapse and update

Upon measuring the first spin, the wavefunction collapses to the state corresponding to the measured outcome. This collapsed wavefunction is then normalized.
The reduced density matrix of the second spin is recalculated using the collapsed wavefunction.

Second spin measurement

The probability of the second spin being +1 is calculated using the updated density matrix:

P(\text{spin 2} = +1 | \text{spin 1}) = \text{Tr}(P_+ \rho_2)

random number is again generated to determine the measurement outcome of the second spin.

The routine follows these steps to ensure that the probabilities of measuring each spin are consistent with quantum mechanics principles. The density matrix allows for the correct representation of entangled states and ensures the outcomes adhere to the non-local correlations predicted by quantum theory. By projecting the wavefunction onto the measured spin state and recalculating the probabilities for the second spin, the function accurately simulates the quantum mechanical behavior of entangled particles.

Visualization

The visualization of the measurement process and results is handled by OpenGL. The apparatus and results are drawn in a 3D space, providing a clear and intuitive representation of the experiment. Here is an example of how the apparatus is drawn:


def drawApparatus(self, app1: bool):
    self.drawApparatusB()
    self.drawLetters()
    self.drawResults(app1)
    button = self.button1 if app1 else self.button2
    if button is not None:
        self.drawButtonSelected(button)
    self.drawApparatusW()
    self.drawArrows(button, app1)

Conclusion

This program serves as a powerful tool for visualizing and understanding the EPR experiment and the fundamental principles of quantum mechanics. By simulating different entangled states and allowing for customizable measurements, it provides a comprehensive platform for exploring the implications of quantum entanglement.

The detailed theoretical background can be explored here. If you’re interested in experimenting with the code and running your own simulations, you can access the full source on GitHub here.