Spaces:
Sleeping
Sleeping
File size: 7,668 Bytes
33f466b a041400 c5bc04e 33f466b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
import numpy as np
import pandas as pd
import streamlit as st
from matplotlib import pyplot as plt
from physics.particles import OneBitEntangledPhoton, LocalDeterministicPhoton
def main():
st.write("# Object Oriented Bell Violation")
st.write(
"""
This is a part of the coding challenge for [EPR Labs](https://epr-labs.com) data-science internship for physicists.
The challenge is to implement a non-local model of a pair of entangled particles that recreates
the results of Bell-violating EPR experiments through a Monte Carlo simulation.
"""
)
st.write(
"""
Particle class should inherid `PolarizedParticleBase` – for simplicity you can assume
it's a photon, and we're interested in measuring polarization given a detector at an angle.
"""
)
code = """
class PolarizedParticleBase(ABC):
@abstractmethod
def measure_polarization(self, detector_angle_rad: float) -> PolarizationMeasurementOutcome:
pass
"""
st.code(code, language="python")
st.write(
"""
The Monte Carlo simulation should perform at least 10k measurements of an entangled
pair with random detector angles. We're interested in tracking the information about
detector angles and measurement outputs. Here's an overview of what the simulation loop can look like:
"""
)
code = """
results = []
for it in range(100_000):
a_photon = YourPhoton(...)
b_photon = YourPhoton(...)
# Your entanglement mechanism
a_photon.entangle(b_photon)
# We are interested only in the angle difference in range [0, pi/2]
a_detector_angle = 0
b_detector_angle = np.random.random() * np.pi / 2
a_polarization_status = a_photon.measure_polarization(a_detector_angle)
b_polarization_status = b_photon.measure_polarization(b_detector_angle)
result = {
"a_outcome": a_polarization_status.value,
"b_outcome": b_polarization_status.value,
"a_detector": a_detector_angle,
"b_detector": b_detector_angle,
}
results.append(result)
"""
st.code(code, language="python")
st.write(
"""
Below you can see results for two different simulations.
One for a local hidden variables model, which fails to violate Bell inequalities,
and one for a model with 1-bit non-local communication, that violates Bell inequalities, but
fails to reproduce empirical results.
"""
)
st.write("## Local Photon Model")
st.write("What Einstein hoped for 🥲")
df = run_local_experiment()
df["angle_bin"] = df.angle_diff.round(2)
# TODO: Write an experiment results wrapper class & nice chart
angle_agreement = df.groupby("angle_bin").agreement.mean().reset_index()
fig = draw_polarization_agreement_chart(agreement_df=angle_agreement)
st.pyplot(fig)
st.write("## 1-bit superluminal communication")
st.write(
"This simulation recreates a model proposed by T.Maudlin in 1992 [[1](https://www.jstor.org/stable/192771)]."
)
df = run_entangled_experiment()
df["angle_bin"] = df.angle_diff.round(2)
# TODO: Write an experiment results wrapper class & nice chart
angle_agreement = df.groupby("angle_bin").agreement.mean().reset_index()
fig = draw_polarization_agreement_chart(agreement_df=angle_agreement)
st.pyplot(fig)
st.write("---")
st.write(
"""
Recruitment has not yet started. If this seems interesting to you, follow us on linkedin for updates:
https://linkedin.com/company/epr-labs
"""
)
# show_refs()
def show_refs():
title = "The Communication Cost of Simulating Bell Correlations"
link = "https://arxiv.org/abs/quant-ph/0304076"
st.write(f"[{title}]({link})")
def draw_polarization_agreement_chart(agreement_df: pd.DataFrame):
fig, ax = plt.subplots(figsize=[9, 4])
x = agreement_df.angle_bin.values * 180 / np.pi
ax.plot(
x,
agreement_df.agreement,
".",
ms=7,
label="this simulation",
color="indigo",
)
ax.plot(
x,
np.cos(agreement_df.angle_bin) ** 2,
label="EPR experiments",
color="teal",
)
ax.set_xlabel("Detectors angle difference [degrees]", fontsize=14)
ax.set_ylabel(
"Proportion of agreement in\nspace time separated\npolarization angle measurements",
fontsize=14,
)
ax.set_ylim(0, 1)
ax.set_xlim(0, x.max())
ax.legend()
y_down = np.zeros_like(x)
# y_up = np.ones_like(x)
y_diagonal = np.linspace(1, 0, len(x))
ax.fill_between(x, y_down, y_diagonal, color="gray", alpha=0.2)
ax.text(10.3, 0.3, "Possible with\nBell-local theory", fontsize=20, rotation=0)
# ax.fill_between(x, y_diagonal, y_up, color="gray", alpha=0.4)
ax.text(54.3, 0.50, "Not possible with\nBell-local theory", fontsize=20, rotation=0)
return fig
def run_entangled_experiment(n_steps: int = 100_000) -> pd.DataFrame:
results = []
for it in range(n_steps):
reference_angle = np.random.random() * np.pi
a_photon = OneBitEntangledPhoton(reference_angle)
b_photon = OneBitEntangledPhoton(reference_angle)
a_photon.entangle(b_photon)
b_photon.entangle(a_photon)
# We are interested in the angle difference between detectors
# and we only want to measure within range of [0 - pi/2] ...
a_detector_angle = 0
# ... so we only allow the movement of the second detector within that range
b_detector_angle = np.random.random() * np.pi / 2
a_polarization_status = a_photon.measure_polarization(a_detector_angle)
b_polarization_status = b_photon.measure_polarization(b_detector_angle)
result = {
"a_outcome": a_polarization_status.value,
"b_outcome": b_polarization_status.value,
"a_detector": a_detector_angle,
"b_detector": b_detector_angle,
}
results.append(result)
df = pd.DataFrame(results)
df["agreement"] = df.a_outcome == df.b_outcome
df["angle_diff"] = df.b_detector - df.a_detector
return df
def run_local_experiment(n_steps: int = 100_000) -> pd.DataFrame:
results = []
for it in range(n_steps):
# In the experimental setup we have photons with same polarization
polarization_angle = np.random.random() * np.pi
a_photon = LocalDeterministicPhoton(polarization_angle)
b_photon = LocalDeterministicPhoton(polarization_angle)
# We are interested in the angle difference between detectors
# and we only want to measure within range of [0 - pi/2] ...
a_detector_angle = 0
# ... so we only allow the movement of the second detector within that range
b_detector_angle = np.random.random() * np.pi / 2
# Without entanglement order of measurement doesn't matter
# (does it matter with entangled particles? :thinking:)
a_polarization_status = a_photon.measure_polarization(a_detector_angle)
b_polarization_status = b_photon.measure_polarization(b_detector_angle)
result = {
"a_outcome": a_polarization_status.value,
"b_outcome": b_polarization_status.value,
"a_detector": a_detector_angle,
"b_detector": b_detector_angle,
}
results.append(result)
df = pd.DataFrame(results)
df["agreement"] = df.a_outcome == df.b_outcome
df["angle_diff"] = df.b_detector - df.a_detector
return df
if __name__ == "__main__":
main()
|