Unverified Commit 5acee0cd authored by dwuggh's avatar dwuggh
Browse files

fix bugs

parent ad4637d6
......@@ -22,10 +22,10 @@ class DensityOperator(QOperator):
# mat = np.outer(ground_state, ground_state)
super().__init__(qubits, mat)
def print(self):
print("qubits: ", self.qubits)
print("shape: ", self.operator.shape)
print(self.operator)
# def print(self):
# print("qubits: ", self.qubits)
# print("shape: ", self.operator.shape)
# print(self.operator)
def merge(self, other):
op = multiply(self, other)
......@@ -35,9 +35,8 @@ class DensityOperator(QOperator):
def evolution(self, unitary: QOperator, p_g = 0, on_qubits = None):
# ρ = U ρ U^\dagger
if on_qubits is not None:
unitary.alter_qubits(on_qubits)
unitary = unitary.alter_qubits(on_qubits)
result = multiply(unitary, multiply(self, unitary.dagger()))
......@@ -62,20 +61,20 @@ class DensityOperator(QOperator):
return result
# bell measurement: only result 00 and 11 will be reserved
def bell_meausure(self, q1, q2, pauli, p_m = 0):
def bell_measure(self, q1, q2, pauli, p_m = 0):
channel1 = measure_x(q1) if pauli == 'x' else measure_z(q2)
channel2 = measure_x(q1) if pauli == 'x' else measure_z(q2)
P_00 = multiply(channel1.kraus_operators[0], channel2.kraus_operators[0])
P_11 = multiply(channel1.kraus_operators[1], channel2.kraus_operators[1])
# this channel will cause probability loss because of post-selection
loss_channel = QChannel([P_00, P_11])
self.print()
# self.print()
self.channel(loss_channel)
self.print()
# self.print()
operator = self.partial_trace([q1, q2])
self.operator = operator.operator
self.qubits = operator.qubits
self.print()
# self.print()
......
import numpy as np
from numpy import dtype
from utils import *
class QOperator(object):
......@@ -16,9 +17,15 @@ class QOperator(object):
# the following should be equivalent:
# return 2 ** self.qubits.size
return self.operator.shape[0]
def print(self):
print("qubits: ", self.qubits)
print("shape: ", self.operator.shape)
print(self.operator)
def alter_qubits(self, qubits):
self.qubits = np.array(qubits)
qubits = np.array(qubits)
return QOperator(qubits, self.operator)
# construct gate in the big hilbert space
# G = I ⊗ G
......@@ -44,6 +51,48 @@ class QOperator(object):
big_operator[i, j] = val
return big_operator
def broadcast_with(self, qubits):
# qubits_new = np.fromiter((x for x in qubits if not contains(self.qubits, x)), dtype=np.int32)
qnum = len(qubits)
dim = 2 ** qnum
big_operator = np.zeros((dim, dim), dtype=np.complex64)
# occupied qubits of the original operator
# we need to respect the order of self.qubits in `qubits`
# occupy1: original qubits in parameter's order
# occupy1 = []
# for i, q in enumerate(qubits):
# if contains(self.qubits, q):
# occupy1.append(q)
# occupy: original qubits index in `self.qubits` of occupy1
occupy = []
for q1 in self.qubits:
for i, q2 in enumerate(qubits):
if q1 == q2:
occupy.append(i)
break
# self.qubits = np.array(qubits)
for i in range(dim):
for j in range(dim):
di = np.flip(get_bin_digits(i, qnum))
dj = np.flip(get_bin_digits(j, qnum))
# coordinates in the small Hilbert space
gi = from_bin_digits(np.flip(di[occupy]))
gj = from_bin_digits(np.flip(dj[occupy]))
# check for identity
id = 1
for k in range(len(di)):
if id == 1 and not contains(occupy, k) and di[k] != dj[k]:
id = 0
val = np.complex64(id) * self.operator[gi, gj]
big_operator[i, j] = val
return QOperator(qubits, big_operator)
# def rearrange(self, qubits_new):
# pass
......@@ -59,23 +108,30 @@ class QOperator(object):
qubits_reserved = np.fromiter((x for x in self.qubits if not contains(traced_qubits, x)), np.int32)
dim_new = dim - 2 ** len(traced_qubits)
# for simplicity, we treat scalar as a matrix of dim (1, 1)
dim_new = dim_new if dim_new > 0 else 1
dim_new = 2 ** len(qubits_reserved)
# the traced matrix
mat_new = np.zeros((dim_new, dim_new), dtype=np.complex64)
# occupied qubits of the original operator
occupy_traced = []
occupy_reserved = []
for i, q in enumerate(self.qubits):
if contains(qubits_reserved, q):
occupy_reserved.append(i)
if contains(traced_qubits, q):
occupy_traced.append(i)
for i in range(dim):
for j in range(dim):
di = np.flip(get_bin_digits(i, qnum))
dj = np.flip(get_bin_digits(j, qnum))
tr_i = from_bin_digits(np.flip(di[traced_qubits]))
tr_j = from_bin_digits(np.flip(dj[traced_qubits]))
tr_i = from_bin_digits(np.flip(di[occupy_traced]))
tr_j = from_bin_digits(np.flip(dj[occupy_traced]))
i_new = from_bin_digits(np.flip(di[qubits_reserved]))
j_new = from_bin_digits(np.flip(dj[qubits_reserved]))
i_new = from_bin_digits(np.flip(di[occupy_reserved]))
j_new = from_bin_digits(np.flip(dj[occupy_reserved]))
if tr_i == tr_j:
# print(i, j, i_new, j_new)
mat_new[i_new, j_new] += self.operator[i, j]
......@@ -86,22 +142,24 @@ class QOperator(object):
def multiply(lhs: QOperator, rhs: QOperator):
q1 = lhs.qubits
q2 = rhs.qubits
qmax = np.max(np.concatenate((q1, q2))) + 1
lhs_big = lhs.broadcast(qmax)
rhs_big = rhs.broadcast(qmax)
result_mat = np.matmul(lhs_big, rhs_big)
result_qubits = [i for i in range(qmax)]
return QOperator(result_qubits, result_mat)
qubits = merge(q1, q2)
# print(q1, q2, qubits)
lhs_big = lhs.broadcast_with(qubits)
# print("lhs", lhs.operator.trace())
rhs_big = rhs.broadcast_with(qubits)
# print("rhs", rhs.operator.trace())
result_mat = np.matmul(lhs_big.operator, rhs_big.operator)
# print("result", result_mat.trace())
return QOperator(qubits, result_mat)
def add(lhs: QOperator, rhs: QOperator):
q1 = lhs.qubits
q2 = rhs.qubits
qmax = np.max(np.concatenate((q1, q2))) + 1
lhs_big = lhs.broadcast(qmax)
rhs_big = rhs.broadcast(qmax)
result_mat = lhs_big + rhs_big
result_qubits = [i for i in range(qmax)]
return QOperator(result_qubits, result_mat)
qubits = merge(q1, q2)
lhs_big = lhs.broadcast_with(qubits)
rhs_big = rhs.broadcast_with(qubits)
result_mat = lhs_big.operator + rhs_big.operator
return QOperator(qubits, result_mat)
# the identity operator I
def identity(qubits=[0]):
......
......@@ -19,26 +19,29 @@ data2 ------σ------------
'''
def nickerson_1(ρ: DensityOperator, err_model: ErrorModel, data1, data2, q1, q2, q3 ,q4, pauli):
ρ1 = bell_pair(err_model.p_n, [q1, q3])
ρ2 = bell_pair(err_model.p_n, [q2, q4])
ρ.merge(ρ1)
ρ.merge(ρ2)
ρ.print()
# 2 control-pauli gate
c1 = cpauli(pauli, [q1, data1])
c2 = cpauli(pauli, [q2, data2])
c2 = cpauli(pauli, [q3, data2])
ρ.evolution(c1, err_model.p_g)
ρ.evolution(c2, err_model.p_g)
ρ.print()
ρ2 = bell_pair(err_model.p_n, [q2, q4])
ρ.merge(ρ2)
c3 = cphase([q2, q1])
c4 = cphase([q4, q3])
ρ.evolution(c1, err_model.p_g)
ρ.evolution(c2, err_model.p_g)
ρ.evolution(c3, err_model.p_g)
ρ.evolution(c4, err_model.p_g)
# measurement
ρ.bell_meausure(q1, q3, 'x', err_model.p_m)
ρ.bell_meausure(q1, q4, 'x', err_model.p_m)
ρ.bell_measure(q1, q3, 'x', err_model.p_m)
ρ.bell_measure(q2, q4, 'x', err_model.p_m)
return ρ
......@@ -47,11 +50,11 @@ q1, q2, q3, q4 are the 4 ancilla qubits
`stringent_plus` indicates whether the blank-separated region is performed
q2 ------∎--⊤--M(x)--∎--⊤--M(x)---- --∎--⊤--M(x)-- ------
q1 ---∎--|--X--------|--Z-------⊤-- --|--Z-------- --M(x)
data1 ---|--|-----------|----------σ-- --|----------- --------
data1 ---|--|-----------|----------σ-- --|----------- ------
| | | |
q4 ---|--∎--⊤--M(x)--∎--⊤--M(x)---- --∎--⊤--M(x)-- ------
q3 ---∎-----X-----------Z-------⊤-- -----Z-------- --M(x)
data2 -----------------------------σ-- -------------- --------
data2 -----------------------------σ-- -------------- ------
'''
def nickerson_2(ρ: DensityOperator, err_model: ErrorModel, data1, data2, q1, q2, q3 ,q4, pauli, stringent_plus = True):
ρ1 = bell_pair(err_model.p_n, [q1, q3])
......@@ -65,7 +68,7 @@ def nickerson_2(ρ: DensityOperator, err_model: ErrorModel, data1, data2, q1, q2
ρ.evolution(c1, err_model.p_g)
ρ.evolution(c2, err_model.p_g)
ρ.bell_meausure(q2, q4, 'x', err_model.p_m)
ρ.bell_measure(q2, q4, 'x', err_model.p_m)
ρ3 = bell_pair(err_model.p_n, [q2, q4])
ρ.merge(ρ2)
......@@ -75,7 +78,7 @@ def nickerson_2(ρ: DensityOperator, err_model: ErrorModel, data1, data2, q1, q2
ρ.evolution(c3, err_model.p_g)
ρ.evolution(c4, err_model.p_g)
ρ.bell_meausure(q2, q4, 'x', err_model.p_m)
ρ.bell_measure(q2, q4, 'x', err_model.p_m)
c5 = cpauli(pauli, [q1, data1])
c6 = cpauli(pauli, [q3, data2])
......@@ -91,11 +94,11 @@ def nickerson_2(ρ: DensityOperator, err_model: ErrorModel, data1, data2, q1, q2
ρ.evolution(c7, err_model.p_g)
ρ.evolution(c8, err_model.p_g)
ρ.bell_meausure(q2, q4, 'x', err_model.p_m)
ρ.bell_measure(q2, q4, 'x', err_model.p_m)
pass
ρ.bell_meausure(q1, q3, 'x', err_model.p_m)
ρ.bell_measure(q1, q3, 'x', err_model.p_m)
'''
2 5
......@@ -118,4 +121,4 @@ def make_GHZ(ρ1: DensityOperator, ρ2: DensityOperator, err_model: ErrorModel,
def stablizer_measurement(err_model: ErrorModel, stringent = True, stringent_plus = True):
ρ1 = make_bell(err_model, stringent, stringent_plus)
ρ2 = make_bell(err_model, stringent, stringent_plus)
ρ2.alter_qubits([6, 9])
ρ2 = ρ2.alter_qubits([6, 9])
from QOperator import pauli
from utils import ErrorModel
import calc_channel as cc
import numpy as np
ρ = cc.DensityOperator(1, np.array([[1, 0], [0, 0]]))
channel = cc.depolarizing_channel(0.01)
ρ.channel(channel)
# ρ = cc.DensityOperator(1, np.array([[1, 0], [0, 0]]))
# channel = cc.depolarizing_channel(0.01)
# ρ.channel(channel)
cnot = cc.cnot()
x = cc.σ_x()
z = cc.σ_z()
# cnot = cc.cnot()
# x = cc.σ_x()
# z = cc.σ_z()
r = cc.multiply(z, cnot)
r = cc.multiply(r, z)
# print(ρ.operator)
print(r.operator)
# r = cc.multiply(z, cnot)
# r = cc.multiply(r, z)
# # print(ρ.operator)
# print(r.operator)
'''
......@@ -24,3 +26,63 @@ D: 9, 10, 11
'''
# np.array([[ 0.12499996+0.j, 0.12499996+0.j, 0.12499996+0.j,
# -0.12499996+0.j],
# [ 0. +0.j, 0. +0.j, 0. +0.j,
# 0. +0.j],
# [ 0. +0.j, 0. +0.j, 0. +0.j,
# 0. +0.j],
# [ 0.12499996+0.j, 0.12499996+0.j, 0.12499996+0.j,
# -0.12499996+0.j]], dtype=np.complex64)
def test_1():
np.set_printoptions(edgeitems=16, linewidth=200,
# formatter=dict(float=lambda x: "%.3g" % x)
)
err_model = cc.ErrorModel()
ρ1 = cc.bell_pair(err_model.p_n, [1, 3])
ρ2 = cc.bell_pair(err_model.p_n, [2, 4])
# ρ1.print()
# print(ρ1.operator.trace())
ρ1.merge(ρ2)
# ρ1.print()
print("trace of ρ1", ρ1.operator.trace())
# ρ1.print()
c1 =cc.cphase([2, 1])
c2 =cc.cphase([4, 3])
ρ1.evolution(c1)
ρ1.evolution(c2)
print("trace of ρ1", ρ1.operator.trace())
ρ1.bell_measure(2, 4, 'z')
ρ1.print()
return ρ1
def test_2():
x = cc.pauli_x(1)
z = cc.pauli_z(0)
a = x.broadcast_with([1, 0])
# x.print()
# z.print()
a = cc.multiply(x, z)
a.print()
a = a.broadcast_with([0, 1])
a.print()
def test_3():
ρ = cc.bell_pair(0)
ρ.bell_measure(0, 1, 'x')
ρ.print()
if __name__ == "__main__":
# a = test_1()
# test_3()
np.set_printoptions(edgeitems=16, linewidth=200,
formatter=dict(complexfloat=lambda x: "%5.6g" % x)
)
err_model = cc.ErrorModel()
ρ = cc.make_bell(err_model, False, False)
ρ.print()
# test_2()
......@@ -47,3 +47,16 @@ class ErrorModel(object):
self.p_n = p_n
self.p_g = p_g
self.p_m = p_m
def merge(l1, l2):
l = []
for i in l1:
if not contains(l, i):
l.append(i)
for i in l2:
if not contains(l, i):
l.append(i)
return np.array(l)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment