{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Bell and CHSH inequalities\n",
"$\\newcommand{\\bra}[1]{\\left\\langle{#1}\\right|}$\n",
"$\\newcommand{\\ket}[1]{\\left|{#1}\\right\\rangle}$\n",
"\n",
"The purpose of this notebook is to simulate the CHSH experiment\n",
"described in the IBM Quantum Experience tutorial in the section\n",
"entitled \n",
"\n",
">Multiple Qubits, Gates, and Entangled States/Entanglement and Bell Tests"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First change your working directory to the qubiter directory in your computer, and add its path to the path environment variable."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/rrtucci/PycharmProjects/qubiter/qubiter/jupyter_notebooks\n",
"/home/rrtucci/PycharmProjects/qubiter\n"
]
}
],
"source": [
"import os\n",
"import sys\n",
"print(os.getcwd())\n",
"os.chdir('../../')\n",
"print(os.getcwd())\n",
"sys.path.insert(0,os.getcwd())"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"loaded OneQubitGate, WITHOUT autograd.numpy\n"
]
}
],
"source": [
"from qubiter.SEO_writer import *\n",
"from qubiter.SEO_simulator import *\n",
"from qubiter.StateVec import *\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, we define matrices $S, T, H, \\sigma_X, \\sigma_Y, \\sigma_Z, I_2$.\n",
"We will denote the Pauli matrices by $\\sigma_X, \\sigma_Y, \\sigma_Z$\n",
"\n",
"Recal that\n",
"\n",
"$S = diag(1, i) = e^{i \\frac{\\pi}{4}} e^{-i \\frac{\\pi}{4} \\sigma_Z}$\n",
"\n",
"$T = diag(1, e^{i \\frac{\\pi}{4}}) = e^{i \\frac{\\pi}{8}} e^{-i \\frac{\\pi}{8} \\sigma_Z}$\n",
"\n",
"$H = \\frac{1}{\\sqrt{2}}(\\sigma_Z + \\sigma_X)$\n",
"\n",
"$H^2 = 1$\n",
"\n",
"$H\\sigma_X H = \\sigma_Z$\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"smat = np.matrix([[1, 0], [0, 1j]])\n",
"tmat = np.matrix([[1, 0], [0, np.exp(1j*np.pi/4)]])\n",
"had = np.matrix([[1, 1], [1, -1]])/np.sqrt(2)\n",
"sigx = np.matrix([[0, 1], [1, 0]])\n",
"sigy = np.matrix([[0, -1j], [1j, 0]])\n",
"sigz = np.matrix([[1, 0], [0, -1]])\n",
"id2 = np.matrix([[1, 0], [0, 1]])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Define $\\sigma_{n} = \\hat{n}\\cdot\\vec{\\sigma}$\n",
"for any 3dim unit vector $\\hat{n}$.\n",
"\n",
"Recall that \n",
"\n",
"$\\sigma_Z\\ket{0_Z} = \\ket{0_Z}$\n",
"\n",
"$\\sigma_Z\\ket{1_Z} = -\\ket{1_Z}$,\n",
"\n",
"or, more succinctly, \n",
"\n",
"$\\sigma_Z\\ket{b_Z} = (-1)^b\\ket{b_Z}$\n",
"\n",
"for $b=0,1$.\n",
"\n",
"Likewise,\n",
"\n",
"$\\sigma_n\\ket{b_n} = (-1)^b\\ket{b_n}$\n",
"\n",
"for any 3dim unit vector $\\hat{n}$ and $b=0, 1$.\n",
"\n",
"One can show by Taylor expansion that\n",
"\n",
"$e^{i\\theta \\sigma_n} = \\cos(\\theta) + i\\sigma_n \\sin(\\theta)$"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def exp_mat2(theta, vec4):\n",
" # vec4 is 4 dimensional np.array. Zero component not used.\n",
" unit_vec = np.array([0, vec4[1], vec4[2], vec4[3]])\n",
" unit_vec = unit_vec/np.linalg.norm(unit_vec)\n",
"\n",
" mat = unit_vec[1]*sigx + unit_vec[2]*sigy + unit_vec[3]*sigz\n",
" return np.cos(theta)*id2 + 1j*mat*np.sin(theta)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Define\n",
"\n",
"$roty = e^{i \\frac{\\pi}{8}\\sigma_Y}$\n",
"\n",
"$\\hat{w} = \\frac{1}{\\sqrt{2}}(\\hat{x} + \\hat{z})$\n",
"\n",
"$\\hat{v} = \\frac{1}{\\sqrt{2}}(-\\hat{x} + \\hat{z})$\n",
"\n",
"$sigw = \\sigma_W = \\frac{1}{\\sqrt{2}}(\\sigma_X + \\sigma_Z)$\n",
"\n",
"$sigv = \\sigma_V = \\frac{1}{\\sqrt{2}}(-\\sigma_X + \\sigma_Z)$\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"roty = exp_mat2(np.pi/8, np.array([0, 0, 1, 0]))\n",
"sigw = (sigx + sigz)/np.sqrt(2)\n",
"sigv = (-sigx + sigz)/np.sqrt(2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check that\n",
"\n",
"$\\sigma_W = e^{-i \\frac{\\pi}{8}\\sigma_Y}\\sigma_Z e^{i \\frac{\\pi}{8}\\sigma_Y}$\n",
"\n",
"$\\sigma_V = e^{i \\frac{\\pi}{8}\\sigma_Y}\\sigma_Z e^{-i \\frac{\\pi}{8}\\sigma_Y}$"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.5700924586837752e-16\n",
"1.5700924586837752e-16\n"
]
}
],
"source": [
"print(np.linalg.norm(sigw - roty.getH()*sigz*roty))\n",
"print(np.linalg.norm(sigv - roty*sigz*roty.getH()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Check that\n",
"\n",
"$ e^{i \\frac{\\pi}{8}\\sigma_Y} = e^{-i \\frac{\\pi}{8}} S^\\dagger H T H S$"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3.9641608582688534e-16\n"
]
}
],
"source": [
"roty1 = np.exp(-1j*np.pi/8)*smat.getH()*had*tmat*had*smat\n",
"print(np.linalg.norm(roty - roty1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Therefore, (Note that $S$ and $\\sigma_Z$ are both diagonal so they commute)\n",
"\n",
"$\\sigma_W = (S^\\dagger H T^\\dagger H S) \\sigma_Z (S^\\dagger H T H S)=\n",
"(S^\\dagger H T^\\dagger H ) \\sigma_Z ( H T H S)$\n",
"\n",
"$\\sigma_V =\n",
"(S^\\dagger H T H ) \\sigma_Z ( H T^\\dagger H S)$\n",
"\n",
"Note that \n",
"\n",
"$\\sigma_Z =\\ket{0_Z}\\bra{0_Z} - \\ket{1_Z}\\bra{1_Z} $\n",
"\n",
"so the same is true if we replace the $Z$ by $W$ or $V$ or any 3dim unit vector.\n",
"\n",
"Therefore,\n",
"a W measurement $\\bra{b_W}$ is related to a Z measurment $\\bra{ b_Z}$ by\n",
"\n",
"$\\bra{ b_W} = \\bra{ b_Z} H T H S$\n",
"\n",
"Likewise, \n",
"\n",
"$\\bra{ b_V} = \\bra{ b_Z} H T^\\dagger H S$\n",
"\n",
"for $b= 0, 1$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that\n",
"\n",
"$\\bra{\\psi} \\sigma_A(0) \\sigma_B(1)\\ket{\\psi}\n",
"=\\bra{\\psi}\n",
"\\begin{array}{c}\n",
"(\\ket{0_A}\\bra{0_A} - \\ket{1_A}\\bra{1_A} )(0)\n",
"\\\\\n",
"(\\ket{0_B}\\bra{0_B} - \\ket{1_B}\\bra{1_B})(1)\n",
"\\end{array}\n",
"\\ket{\\psi}$\n",
"\n",
"so \n",
"\n",
"$\\bra{\\psi} \\sigma_A(0) \\sigma_B(1)\\ket{\\psi}\n",
"= Prob(0, 0) + Prob(1, 1) - Prob(0, 1) - Prob(1, 0)$"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def write_bell_plus(file_prefix, bell_only=True, extra_had=False, t_herm=False):\n",
" num_qbits = 2\n",
" z_axis = 3\n",
" emb = CktEmbedder(num_qbits, num_qbits)\n",
" print('-------------------', file_prefix)\n",
" wr = SEO_writer(file_prefix, emb)\n",
" wr.write_one_qbit_gate(0, OneQubitGate.had2)\n",
"\n",
" control_pos = 0\n",
" target_pos = 1\n",
" trols = Controls.new_single_trol(num_qbits, control_pos, kind=True)\n",
" wr.write_controlled_one_qbit_gate(\n",
" target_pos, trols, OneQubitGate.sigx)\n",
"\n",
" if not bell_only:\n",
" if extra_had:\n",
" wr.write_one_qbit_gate(0, OneQubitGate.had2) # H(0)\n",
"\n",
" wr.write_one_qbit_gate(1, OneQubitGate.rot_ax, [-np.pi/4, z_axis]) # S(1)\n",
" wr.write_one_qbit_gate(1, OneQubitGate.had2) # H(1)\n",
" if t_herm:\n",
" pm_one = -1\n",
" else:\n",
" pm_one = 1\n",
" wr.write_one_qbit_gate(1, OneQubitGate.rot_ax,\n",
" [-pm_one*np.pi/8, z_axis]) # T(1) if pm_one=1\n",
" wr.write_one_qbit_gate(1, OneQubitGate.had2) # H(1)\n",
" wr.close_files()\n",
" wr.print_pic_file(jup=True)\n",
" init_st_vec = StateVec.get_standard_basis_st_vec([0, 0])\n",
" sim = SEO_simulator(file_prefix, num_qbits, init_st_vec)\n",
" StateVec.describe_st_vec_dict(sim.cur_st_vec_dict, print_st_vec=True, do_pp=True,\n",
" omit_zero_amps=True, show_pp_probs=True)\n",
" fin_st_vec = sim.cur_st_vec_dict[\"pure\"]\n",
" print('Prob(bit0=j, bit1=k) for j,k=0,1:')\n",
" prob_arr = np.abs(fin_st_vec.arr)**2\n",
" print(prob_arr)\n",
" mean = prob_arr[0, 0] \\\n",
" + prob_arr[1, 1] \\\n",
" - prob_arr[0, 1] \\\n",
" - prob_arr[1, 0]\n",
" print('mean=', mean)\n",
" return mean\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------------------- bell_zz_meas\n"
]
},
{
"data": {
"text/html": [
"
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"*********branch= pure\n",
"state vector:\n",
"ZL convention (Zero bit Last in state tuple)\n",
"(00)ZL ( 0.707107 + 0.000000j)\t prob=0.500000\n",
"(11)ZL ( 0.707107 + 0.000000j)\t prob=0.500000\n",
"total probability of state vector (=one if no measurements)= 1.000000\n",
"dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
"{0: (0.5, 0.5), 1: (0.5, 0.5)}\n",
"Prob(bit0=j, bit1=k) for j,k=0,1:\n",
"[[0.5 0. ]\n",
" [0. 0.5]]\n",
"mean= 0.9999999999999998\n"
]
}
],
"source": [
"# sigz(0)sigz(1) measurement\n",
"file_prefix = 'bell_zz_meas'\n",
"mean_zz = write_bell_plus(file_prefix, bell_only=True)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------------------- bell_zw_meas\n"
]
},
{
"data": {
"text/html": [
"1 | | H |
2 | X---@ | 3 | Rz | | 4 | H | | 5 | Rz | | 6 | H | |
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"*********branch= pure\n",
"state vector:\n",
"ZL convention (Zero bit Last in state tuple)\n",
"(00)ZL ( 0.461940 - 0.461940j)\t prob=0.426777\n",
"(10)ZL (-0.191342 - 0.191342j)\t prob=0.073223\n",
"(01)ZL ( 0.191342 - 0.191342j)\t prob=0.073223\n",
"(11)ZL ( 0.461940 + 0.461940j)\t prob=0.426777\n",
"total probability of state vector (=one if no measurements)= 1.000000\n",
"dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
"{0: (0.5, 0.5), 1: (0.5, 0.5)}\n",
"Prob(bit0=j, bit1=k) for j,k=0,1:\n",
"[[0.4267767 0.0732233]\n",
" [0.0732233 0.4267767]]\n",
"mean= 0.7071067811865472\n"
]
}
],
"source": [
"# sigz(0)sigw(1) measurement\n",
"file_prefix = 'bell_zw_meas'\n",
"mean_zw = write_bell_plus(file_prefix, bell_only=False, extra_had=False, t_herm=False)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------------------- bell_zv_meas\n"
]
},
{
"data": {
"text/html": [
"1 | | H |
2 | X---@ | 3 | Rz | | 4 | H | | 5 | Rz | | 6 | H | |
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"*********branch= pure\n",
"state vector:\n",
"ZL convention (Zero bit Last in state tuple)\n",
"(00)ZL ( 0.461940 - 0.461940j)\t prob=0.426777\n",
"(10)ZL ( 0.191342 + 0.191342j)\t prob=0.073223\n",
"(01)ZL (-0.191342 + 0.191342j)\t prob=0.073223\n",
"(11)ZL ( 0.461940 + 0.461940j)\t prob=0.426777\n",
"total probability of state vector (=one if no measurements)= 1.000000\n",
"dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
"{0: (0.5, 0.5), 1: (0.5, 0.5)}\n",
"Prob(bit0=j, bit1=k) for j,k=0,1:\n",
"[[0.4267767 0.0732233]\n",
" [0.0732233 0.4267767]]\n",
"mean= 0.7071067811865472\n"
]
}
],
"source": [
"# sigz(0)sigv(1) measurement\n",
"file_prefix = 'bell_zv_meas'\n",
"mean_zv = write_bell_plus(file_prefix, bell_only=False, extra_had=False, t_herm=True)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------------------- bell_xw_meas\n"
]
},
{
"data": {
"text/html": [
"1 | | H |
2 | X---@ | 3 | | H | 4 | Rz | | 5 | H | | 6 | Rz | | 7 | H | |
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"*********branch= pure\n",
"state vector:\n",
"ZL convention (Zero bit Last in state tuple)\n",
"(00)ZL ( 0.461940 - 0.461940j)\t prob=0.426777\n",
"(10)ZL ( 0.191342 + 0.191342j)\t prob=0.073223\n",
"(01)ZL ( 0.191342 - 0.191342j)\t prob=0.073223\n",
"(11)ZL (-0.461940 - 0.461940j)\t prob=0.426777\n",
"total probability of state vector (=one if no measurements)= 1.000000\n",
"dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
"{0: (0.5, 0.5), 1: (0.5, 0.5)}\n",
"Prob(bit0=j, bit1=k) for j,k=0,1:\n",
"[[0.4267767 0.0732233]\n",
" [0.0732233 0.4267767]]\n",
"mean= 0.7071067811865469\n"
]
}
],
"source": [
"# sigx(0)sigw(1) measurement\n",
"file_prefix = 'bell_xw_meas'\n",
"mean_xw = write_bell_plus(file_prefix, bell_only=False, extra_had=True, t_herm=False)"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"------------------- bell_xv_meas\n"
]
},
{
"data": {
"text/html": [
"1 | | H |
2 | X---@ | 3 | | H | 4 | Rz | | 5 | H | | 6 | Rz | | 7 | H | |
"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"*********branch= pure\n",
"state vector:\n",
"ZL convention (Zero bit Last in state tuple)\n",
"(00)ZL ( 0.191342 - 0.191342j)\t prob=0.073223\n",
"(10)ZL ( 0.461940 + 0.461940j)\t prob=0.426777\n",
"(01)ZL ( 0.461940 - 0.461940j)\t prob=0.426777\n",
"(11)ZL (-0.191342 - 0.191342j)\t prob=0.073223\n",
"total probability of state vector (=one if no measurements)= 1.000000\n",
"dictionary with key=qubit, value=(Prob(0), Prob(1))\n",
"{0: (0.5, 0.5), 1: (0.5, 0.5)}\n",
"Prob(bit0=j, bit1=k) for j,k=0,1:\n",
"[[0.0732233 0.4267767]\n",
" [0.4267767 0.0732233]]\n",
"mean= -0.7071067811865468\n"
]
}
],
"source": [
"# sigx(0)sigv(1) measurement\n",
"file_prefix = 'bell_xv_meas'\n",
"mean_xv = write_bell_plus(file_prefix, bell_only=False, extra_had=True, t_herm=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let\n",
"\n",
"$mean\\_ab = \\bra{\\psi} \\sigma_A(0) \\sigma_B(1)\\ket{\\psi}$\n",
"\n",
"where\n",
"\n",
"$\\ket{\\psi} = \\frac{1}{\\sqrt{2}}(\\ket{00}+ \\ket{11})$\n",
"\n",
"Ckeck that \n",
"\n",
"$C = mean\\_zw + mean\\_zv + mean\\_xw - mean\\_xv = 2\\sqrt{2}$\n",
"\n",
"The classical analogue of $C$ satisfies $|C| \\leq 2$"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"-----------------------\n",
"mean_zw + mean_zv + mean_xw - mean_xv - 2*np.sqrt(2)= -2.220446049250313e-15\n"
]
}
],
"source": [
"print('-----------------------')\n",
"print('mean_zw + mean_zv + mean_xw - mean_xv - 2*np.sqrt(2)=',\n",
" mean_zw + mean_zv + mean_xw - mean_xv - 2*np.sqrt(2))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.9"
},
"toc": {
"colors": {
"hover_highlight": "#DAA520",
"running_highlight": "#FF0000",
"selected_highlight": "#FFD700"
},
"moveMenuLeft": true,
"nav_menu": {
"height": "30px",
"width": "252px"
},
"navigate_menu": true,
"number_sections": true,
"sideBar": true,
"threshold": 4,
"toc_cell": false,
"toc_section_display": "block",
"toc_window_display": false,
"widenNotebook": false
}
},
"nbformat": 4,
"nbformat_minor": 4
}