Skip to content

Commit

Permalink
moved measure routine for two spin in TwoSpin class
Browse files Browse the repository at this point in the history
  • Loading branch information
azimonti committed May 28, 2024
1 parent eac01a5 commit 0a71941
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 155 deletions.
83 changes: 9 additions & 74 deletions epr_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
'''
/************************/
/* epr_experiment.py */
/* Version 1.0 */
/* 2024/05/12 */
/* Version 1.1 */
/* 2024/05/28 */
/************************/
'''
import argparse
Expand Down Expand Up @@ -125,7 +125,7 @@ def __init__(self, parent):
case _:
raise ValueError(
f"Incorrect simulation type {self.simul_type}")
self.current_state = spin.psi
self.spin = spin
# Initialize the directions which have a defined rotation between
# each other
# First apparatus
Expand Down Expand Up @@ -650,15 +650,15 @@ def measure(self, n):
if random_number < 0.5:

# Simulate measuring the first apparatus
self.measurement1, self.measurement2 = self.measureSpin(
self.measurement1, self.measurement2 = self.spin.Measure(
np.array([self.direction1p[self.button1],
self.direction1m[self.button1]]),
np.array([self.direction2p[self.button2],
self.direction2m[self.button2]]),
True)
else:
# Simulate measuring the second apparatus
self.measurement2, self.measurement1 = self.measureSpin(
self.measurement2, self.measurement1 = self.spin.Measure(
np.array([self.direction1p[self.button1],
self.direction1m[self.button1]]),
np.array([self.direction2p[self.button2],
Expand All @@ -677,74 +677,6 @@ def measure(self, n):
# redraw
self.update()

def measureSpin(self, directions1: np.ndarray,
directions2: np.ndarray, simulate_1: bool):
'''
Perform the measurement of the spin of two directions 1 and 2,
which one to simulate is decided by the caller.
'''
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
# Define the projector operator for the "+1" state
direction1_p1 = np.array(directions1[0])
direction1_m1 = np.array(directions1[1])
direction2_p1 = np.array(directions2[0])
direction2_m1 = np.array(directions2[1])
projector1_p1 = np.outer(direction1_p1, direction1_p1.conj())
projector1_m1 = np.outer(direction1_m1, direction1_m1.conj())
projector2_p1 = np.outer(direction2_p1, direction2_p1.conj())
projector2_m1 = np.outer(direction2_m1, direction2_m1.conj())

if simulate_1:
# Create 4x4 projectors for the two-spin system
projector_p1_s = np.kron(projector1_p1, np.eye(2))
projector_m1_s = np.kron(projector1_m1, np.eye(2))
projector_p11 = projector1_p1
projector_p21 = projector2_p1

# Calculate the reduced density matrix for the first spin
# which is measured
rho_i = Rho1(psi)
else:
projector_p1_s = np.kron(np.eye(2), projector2_p1)
projector_m1_s = np.kron(np.eye(2), projector2_m1)
projector_p11 = projector2_p1
projector_p21 = projector1_p1
rho_i = Rho2(psi)

# Calculate the probability of this first spin being "+1"
prob_p11 = np.linalg.norm(np.trace(np.dot(projector_p11, rho_i)))
# Generate a random number between 0 and 1
random_number1 = random.uniform(0, 1)

# Perform the measurement in apparatus direction
sp1 = 1 if random_number1 < prob_p11 else -1

# reduce psi projecting on the direction
psi_r = np.dot(projector_p1_s, psi) if sp1 == 1 else \
np.dot(projector_m1_s, psi)
# Normalize psi_r
psi_r = psi_r / np.linalg.norm(psi_r)
# Calculate the reduced density matrix for the second spin
# with the collapsed wave function for the first system
rho_j = Rho2(psi_r) if simulate_1 else Rho1(psi_r)

# Calculate the probability of "system 2" being "+1"
prob_p12 = np.linalg.norm(np.trace(np.dot(projector_p21, rho_j)))

# Generate a random number between 0 and 1
random_number2 = random.uniform(0, 1)

sp2 = 1 if random_number2 < prob_p12 else -1
return (sp1, sp2)

def update_button1(self, value: int):
self.button1 = value
self.button1fix = value
Expand Down Expand Up @@ -882,7 +814,10 @@ def initUI(self):
# Set Default
self.radioButtonC1.setChecked(True)
self.radioButtonC2.setChecked(True)
self.radioButtonFix.setChecked(True)
if cfg.experiment < 0:
self.radioButtonFix.setChecked(True)
else:
self.radioButtonRandom.setChecked(True)

self.layout.addLayout(self.gridlayout)

Expand Down
72 changes: 72 additions & 0 deletions mod_spin_operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import cmath
import math
import numpy as np
import random
import sys


Expand Down Expand Up @@ -208,6 +209,77 @@ def Triplet(self, i: int):
case _:
raise ValueError("Incorrect index " + str(i))

def Measure(self, directions1: np.ndarray,
directions2: np.ndarray, simulate_1: bool = True,
update: bool = False):
'''
Perform the measurement of the spin of two directions 1 and 2,
which one to simulate is decided by the caller.
'''
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.__state
# Define the projector operator for the "+1" state
direction1_p1 = np.array(directions1[0])
direction1_m1 = np.array(directions1[1])
direction2_p1 = np.array(directions2[0])
direction2_m1 = np.array(directions2[1])
projector1_p1 = np.outer(direction1_p1, direction1_p1.conj())
projector1_m1 = np.outer(direction1_m1, direction1_m1.conj())
projector2_p1 = np.outer(direction2_p1, direction2_p1.conj())
projector2_m1 = np.outer(direction2_m1, direction2_m1.conj())

if simulate_1:
# Create 4x4 projectors for the two-spin system
projector_p1_s = np.kron(projector1_p1, np.eye(2))
projector_m1_s = np.kron(projector1_m1, np.eye(2))
projector_p11 = projector1_p1
projector_p21 = projector2_p1

# Calculate the reduced density matrix for the first spin
# which is measured
rho_i = Rho1(psi)
else:
projector_p1_s = np.kron(np.eye(2), projector2_p1)
projector_m1_s = np.kron(np.eye(2), projector2_m1)
projector_p11 = projector2_p1
projector_p21 = projector1_p1
rho_i = Rho2(psi)

# Calculate the probability of this first spin being "+1"
prob_p11 = np.linalg.norm(np.trace(np.dot(projector_p11, rho_i)))
# Generate a random number between 0 and 1
random_number1 = random.uniform(0, 1)

# Perform the measurement in apparatus direction
sp1 = 1 if random_number1 < prob_p11 else -1

# reduce psi projecting on the direction
psi_r = np.dot(projector_p1_s, psi) if sp1 == 1 else \
np.dot(projector_m1_s, psi)
# Normalize psi_r
psi_r = psi_r / np.linalg.norm(psi_r)
# Calculate the reduced density matrix for the second spin
# with the collapsed wave function for the first system
rho_j = Rho2(psi_r) if simulate_1 else Rho1(psi_r)

# Calculate the probability of "system 2" being "+1"
prob_p12 = np.linalg.norm(np.trace(np.dot(projector_p21, rho_j)))

# Generate a random number between 0 and 1
random_number2 = random.uniform(0, 1)

sp2 = 1 if random_number2 < prob_p12 else -1
if update:
self.__state = psi
return (sp1, sp2)


if __name__ == '__main__':
if sys.version_info[0] < 3:
Expand Down
4 changes: 2 additions & 2 deletions single_spin_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
'''
/************************/
/* single_spin_sim.py */
/* Version 1.0 */
/* 2024/05/11 */
/* Version 1.1 */
/* 2024/05/28 */
/************************/
'''
import argparse
Expand Down
89 changes: 10 additions & 79 deletions two_spin_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
'''
/************************/
/* two_spin_sim.py */
/* Version 1.0 */
/* 2024/05/11 */
/* Version 1.1 */
/* 2024/05/28 */
/************************/
'''
import argparse
Expand Down Expand Up @@ -128,7 +128,7 @@ def __init__(self, parent):
self.measurementB = None
self.count_p1B = 0
self.count_m1B = 0
self.current_state = None
self.spin = TwoSpin()
self.sigma = {'A': {'x': [], 'y': [], 'z': [], 'th_ph': []},
'B': {'x': [], 'y': [], 'z': [], 'th_ph': []}
}
Expand Down Expand Up @@ -352,10 +352,10 @@ def updateCountA(self, value: int):
self.measurementA = -1

def measureAB(self, current_state: np.ndarray, measureA: bool):
self.current_state = current_state
self.spin.psi = current_state
for axis in ['z', 'x', 'y']:
sp = self.measureSpin(self.directions[axis],
self.directions[axis], True)
sp = self.spin.Measure(self.directions[axis],
self.directions[axis], True)
self.sigma['A'][axis].append(sp[0])
self.sigma['B'][axis].append(sp[1])

Expand All @@ -382,16 +382,16 @@ def measureAB(self, current_state: np.ndarray, measureA: bool):
np.pi / 2 + self.a_thetaB * cfg.bloch_t / 2)])

if measureA:
sp = self.measureSpin(np.array([directionAp, directionAm]),
np.array([directionBp, directionBm]), True)
sp = self.spin.Measure(np.array([directionAp, directionAm]),
np.array([directionBp, directionBm]), True)
self.sigma['A']['th_ph'].append(sp[0])
self.updateCountA(sp[0])
if cfg.m:
self.sigma['B']['th_ph'].append(sp[1])
self.updateCountB(sp[1])
else:
sp = self.measureSpin(np.array([directionAp, directionAm]),
np.array([directionBp, directionBm]), False)
sp = self.spin.Measure(np.array([directionAp, directionAm]),
np.array([directionBp, directionBm]), False)
self.sigma['B']['th_ph'].append(sp[1])
self.updateCountB(sp[1])
if cfg.m:
Expand Down Expand Up @@ -419,75 +419,6 @@ def updateCountB(self, value: int):
self.count_m1B += 1
self.measurementB = -1

def measureSpin(self, directionsA: np.ndarray,
directionsB: np.ndarray, simulate_A: bool):
'''
Perform the measurement of the spin of two systems A and B,
which one to simulate is decided by the caller.
'''
def RhoA(psi: np.ndarray):
return np.outer(psi, psi.conj()).reshape(
(2, 2, 2, 2)).trace(axis1=1, axis2=3)

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

psi = self.current_state
# Define the projector operator for the "+1" state
directionA_p1 = np.array(directionsA[0])
directionA_m1 = np.array(directionsA[1])
directionB_p1 = np.array(directionsB[0])
directionB_m1 = np.array(directionsB[1])

projectorA_p1 = np.outer(directionA_p1, directionA_p1.conj())
projectorA_m1 = np.outer(directionA_m1, directionA_m1.conj())
projectorB_p1 = np.outer(directionB_p1, directionB_p1.conj())
projectorB_m1 = np.outer(directionB_m1, directionB_m1.conj())

if simulate_A:
# Create 4x4 projectors for the two-spin system
projector_p1_s = np.kron(projectorA_p1, np.eye(2))
projector_m1_s = np.kron(projectorA_m1, np.eye(2))
projector_p11 = projectorA_p1
projector_p21 = projectorB_p1

# Calculate the reduced density matrix for the first spin
# which is measured
rho1 = RhoA(psi)
else:
projector_p1_s = np.kron(np.eye(2), projectorB_p1)
projector_m1_s = np.kron(np.eye(2), projectorB_m1)
projector_p11 = projectorB_p1
projector_p21 = projectorA_p1
rho1 = RhoB(psi)

# Calculate the probability of this first spin being "+1"
prob_p11 = np.linalg.norm(np.trace(np.dot(projector_p11, rho1)))
# Generate a random number between 0 and 1
random_number1 = random.uniform(0, 1)

# Perform the measurement in apparatus direction
sp1 = 1 if random_number1 < prob_p11 else -1

# reduce psi projecting on the direction
psi_r = np.dot(projector_p1_s, psi) if sp1 == 1 else \
np.dot(projector_m1_s, psi)
# Normalize psi_r
psi_r = psi_r / np.linalg.norm(psi_r)
# Calculate the reduced density matrix for the second spin
# with the collapsed wave function for the first system
rho2 = RhoB(psi_r) if simulate_A else RhoA(psi_r)

# Calculate the probability of "system 2" being "+1"
prob_p12 = np.linalg.norm(np.trace(np.dot(projector_p21, rho2)))

# Generate a random number between 0 and 1
random_number2 = random.uniform(0, 1)

sp2 = 1 if random_number2 < prob_p12 else -1
return (sp1, sp2) if simulate_A else (sp2, sp1)


class MainWindow(QWidget):

Expand Down

0 comments on commit 0a71941

Please sign in to comment.