$\newcommand{\bra}[1]{\left\langle{#1}\right|}$ $\newcommand{\ket}[1]{\left|{#1}\right\rangle}$
The purpose of this notebook is to simulate the GHZ experiment described in the IBM Quantum Experience tutorial in the section entitled
Multiple Qubits, Gates, and Entangled States/GHZ states
If you understand our "Bell_and_CHSH_inequalities" notebook, this notebook uses very similar math.
It uses the following results whose proofs use techniques already covered in our "Bell_and_CHSH_inequalities" notebook
$\bra{ b_X} = \bra{ b_Z} H$
$\bra{ b_Y} = \bra{ b_Z} H S^\dagger$
for $b=0, 1$.
$\bra{\psi} \sigma_A(0) \sigma_B(1) \sigma_C(2)\ket{\psi} = \sum_{b_0 + b_1 + b_2 = 0, 2} Prob(b_0, b_1, b_2) - \sum_{b_0 + b_1 + b_2 = 1, 3} Prob(b_0, b_1, b_2)$
First change your working directory to the qubiter directory in your computer, and add its path to the path environment variable.
import os
import sys
print(os.getcwd())
os.chdir('../../')
print(os.getcwd())
sys.path.insert(0,os.getcwd())
/home/rrtucci/PycharmProjects/qubiter/qubiter/jupyter_notebooks /home/rrtucci/PycharmProjects/qubiter
from qubiter.SEO_writer import *
from qubiter.SEO_simulator import *
from qubiter.StateVec import *
import numpy as np
loaded OneQubitGate, WITHOUT autograd.numpy
def write_ghz_plus(file_prefix, ghz_only=True, meas=None):
num_qbits = 3
z_axis = 3
emb = CktEmbedder(num_qbits, num_qbits)
print('-------------------', file_prefix)
wr = SEO_writer(file_prefix, emb)
wr.write_one_qbit_gate(0, OneQubitGate.had2)
wr.write_one_qbit_gate(1, OneQubitGate.had2)
wr.write_one_qbit_gate(2, OneQubitGate.sigx)
control_pos = 0
target_pos = 2
trols = Controls.new_single_trol(num_qbits, control_pos, kind=True)
wr.write_controlled_one_qbit_gate(
target_pos, trols, OneQubitGate.sigx)
control_pos = 1
target_pos = 2
trols = Controls.new_single_trol(num_qbits, control_pos, kind=True)
wr.write_controlled_one_qbit_gate(
target_pos, trols, OneQubitGate.sigx)
wr.write_one_qbit_gate(0, OneQubitGate.had2)
wr.write_one_qbit_gate(1, OneQubitGate.had2)
wr.write_one_qbit_gate(2, OneQubitGate.had2)
if not ghz_only:
for pos in range(3):
m = meas[pos]
if m == 1:
wr.write_one_qbit_gate(pos, OneQubitGate.had2)
elif m == 2:
wr.write_one_qbit_gate(pos,
OneQubitGate.rot_ax, [np.pi/4, z_axis]) # S^\dagger(pos)
wr.write_one_qbit_gate(pos, OneQubitGate.had2)
else:
assert False
wr.close_files()
wr.print_pic_file(jup=True)
init_st_vec = StateVec.get_standard_basis_st_vec([0, 0, 0])
sim = SEO_simulator(file_prefix, num_qbits, init_st_vec)
StateVec.describe_st_vec_dict(sim.cur_st_vec_dict, print_st_vec=True, do_pp=True,
omit_zero_amps=True, show_pp_probs=True)
fin_st_vec = sim.cur_st_vec_dict["pure"]
print('Prob(bit0=i, bit1=j, bit2=k) for i,j,k,=0,1:')
prob_arr = np.abs(fin_st_vec.arr)**2
print(prob_arr)
mean = prob_arr[0, 0, 0] \
+ prob_arr[0, 1, 1] \
+ prob_arr[1, 0, 1] \
+ prob_arr[1, 1, 0] \
- prob_arr[1, 1, 1] \
- prob_arr[0, 0, 1] \
- prob_arr[1, 0, 0] \
- prob_arr[0, 1, 0]
print('mean=', mean)
return mean
# sigz(0)sigz(1)sigz(2) measurement
file_prefix = 'ghz_zzz_meas'
mean_zzz = write_ghz_plus(file_prefix, ghz_only=True)
------------------- ghz_zzz_meas
1 | | | H | 2 | | H | | 3 | X | | | 4 | X---+---@ | 5 | X---@ | | 6 | | | H | 7 | | H | | 8 | H | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (000)ZL ( 0.707107 + 0.000000j) prob=0.500000 (111)ZL (-0.707107 + 0.000000j) prob=0.500000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.5, 0.5), 1: (0.5, 0.5), 2: (0.5, 0.5)} Prob(bit0=i, bit1=j, bit2=k) for i,j,k,=0,1: [[[5.00000000e-01 0.00000000e+00] [1.93646401e-37 0.00000000e+00]] [[0.00000000e+00 1.93646401e-37] [0.00000000e+00 5.00000000e-01]]] mean= -1.936464009786347e-37
# sigy(0)sigy(1)sigx(2) measurement
file_prefix = 'ghz_yyx_meas'
mean_yyx = write_ghz_plus(file_prefix, ghz_only=False, meas=[2, 2, 1])
------------------- ghz_yyx_meas
1 | | | H | 2 | | H | | 3 | X | | | 4 | X---+---@ | 5 | X---@ | | 6 | | | H | 7 | | H | | 8 | H | | | 9 | | | Rz | 10 | | | H | 11 | | Rz | | 12 | | H | | 13 | H | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (000)ZL ( 0.000000 + 0.500000j) prob=0.250000 (110)ZL ( 0.000000 + 0.500000j) prob=0.250000 (101)ZL ( 0.000000 + 0.500000j) prob=0.250000 (011)ZL ( 0.000000 + 0.500000j) prob=0.250000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.5, 0.5), 1: (0.5, 0.5), 2: (0.5, 0.5)} Prob(bit0=i, bit1=j, bit2=k) for i,j,k,=0,1: [[[2.50000000e-01 6.98526388e-33] [6.88162536e-33 2.50000000e-01]] [[6.98526388e-33 2.50000000e-01] [2.50000000e-01 6.88162536e-33]]] mean= 0.9999999999999987
# sigy(0)sigx(1)sigy(2) measurement
file_prefix = 'ghz_yxy_meas'
mean_yxy = write_ghz_plus(file_prefix, ghz_only=False, meas=[2, 1, 2])
------------------- ghz_yxy_meas
1 | | | H | 2 | | H | | 3 | X | | | 4 | X---+---@ | 5 | X---@ | | 6 | | | H | 7 | | H | | 8 | H | | | 9 | | | Rz | 10 | | | H | 11 | | H | | 12 | Rz | | | 13 | H | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (000)ZL ( 0.000000 + 0.500000j) prob=0.250000 (110)ZL ( 0.000000 + 0.500000j) prob=0.250000 (101)ZL ( 0.000000 + 0.500000j) prob=0.250000 (011)ZL ( 0.000000 + 0.500000j) prob=0.250000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.5, 0.5), 1: (0.5, 0.5), 2: (0.5, 0.5)} Prob(bit0=i, bit1=j, bit2=k) for i,j,k,=0,1: [[[2.50000000e-01 7.26573057e-33] [7.26573057e-33 2.50000000e-01]] [[7.26573057e-33 2.50000000e-01] [2.50000000e-01 7.26573057e-33]]] mean= 0.9999999999999987
# sigx(0)sigy(1)sigy(2) measurement
file_prefix = 'ghz_xyy_meas'
mean_xyy = write_ghz_plus(file_prefix, ghz_only=False, meas=[1, 2, 2])
------------------- ghz_xyy_meas
1 | | | H | 2 | | H | | 3 | X | | | 4 | X---+---@ | 5 | X---@ | | 6 | | | H | 7 | | H | | 8 | H | | | 9 | | | H | 10 | | Rz | | 11 | | H | | 12 | Rz | | | 13 | H | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (000)ZL ( 0.000000 + 0.500000j) prob=0.250000 (110)ZL ( 0.000000 + 0.500000j) prob=0.250000 (101)ZL ( 0.000000 + 0.500000j) prob=0.250000 (011)ZL ( 0.000000 + 0.500000j) prob=0.250000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.5, 0.5), 1: (0.5, 0.5), 2: (0.5, 0.5)} Prob(bit0=i, bit1=j, bit2=k) for i,j,k,=0,1: [[[2.50000000e-01 7.26573057e-33] [7.26573057e-33 2.50000000e-01]] [[7.26573057e-33 2.50000000e-01] [2.50000000e-01 7.26573057e-33]]] mean= 0.9999999999999987
# sigx(0)sigx(1)sigx(2) measurement
file_prefix = 'ghz_xxx_meas'
mean_xxx = write_ghz_plus(file_prefix, ghz_only=False, meas=[1, 1, 1])
------------------- ghz_xxx_meas
1 | | | H | 2 | | H | | 3 | X | | | 4 | X---+---@ | 5 | X---@ | | 6 | | | H | 7 | | H | | 8 | H | | | 9 | | | H | 10 | | H | | 11 | H | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (100)ZL ( 0.500000 + 0.000000j) prob=0.250000 (010)ZL ( 0.500000 + 0.000000j) prob=0.250000 (001)ZL ( 0.500000 + 0.000000j) prob=0.250000 (111)ZL ( 0.500000 + 0.000000j) prob=0.250000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.5, 0.5), 1: (0.5, 0.5), 2: (0.5, 0.5)} Prob(bit0=i, bit1=j, bit2=k) for i,j,k,=0,1: [[[0. 0.25] [0.25 0. ]] [[0.25 0. ] [0. 0.25]]] mean= -0.9999999999999987
Let
$mean\_abc = \bra{\psi} \sigma_A(0) \sigma_B(1)\sigma_C(2)\ket{\psi}$
where
$\ket{\psi} = \frac{1}{\sqrt{2}}(\ket{000} + \ket{111})$
We expect
$mean\_yyx = mean\_yxy = mean\_xyy = 1$
and
$mean\_xxx=-1$.
This could never happen classically.
print('-----------------------')
print('mean_yyx =', mean_yyx)
print('mean_yxy =', mean_yxy)
print('mean_xyy =', mean_xyy)
print('mean_xxx =', mean_xxx)
----------------------- mean_yyx = 0.9999999999999987 mean_yxy = 0.9999999999999987 mean_xyy = 0.9999999999999987 mean_xxx = -0.9999999999999987