cnot is generalized to two qubit gate

This commit is contained in:
Daniel Tsvetkov 2020-02-03 16:15:00 +01:00
parent 402ac81f2a
commit 4c4f6bd43b

View File

@ -428,7 +428,7 @@ class HermitianOperator(LinearOperator, HermitianMatrix):
return str(self.m) return str(self.m)
# TODO - How to add a CNOT gate to the Quantum Processor? # How to add a CNOT gate to the Quantum Processor?
# Imagine if I have to act on a 3-qubit computer and CNOT(q1, q3) # Imagine if I have to act on a 3-qubit computer and CNOT(q1, q3)
# #
# Decomposed CNOT : # Decomposed CNOT :
@ -454,8 +454,8 @@ class TwoQubitPartial(object):
return str("-{}-".format(self.rpr)) return str("-{}-".format(self.rpr))
C_ = TwoQubitPartial("C") C_partial = TwoQubitPartial("C")
x_ = TwoQubitPartial("x") x_partial = TwoQubitPartial("x")
class TwoQubitOperator(UnitaryOperator): class TwoQubitOperator(UnitaryOperator):
@ -468,13 +468,16 @@ class TwoQubitOperator(UnitaryOperator):
self.A_p = A_p self.A_p = A_p
self.B_p = B_p self.B_p = B_p
A.operator = self
B.operator = self
def verify_step(self, step): def verify_step(self, step):
if not (step.count(self.A) == 1 and step.count(self.B) == 1): if not (step.count(self.A) == 1 and step.count(self.B) == 1):
raise RuntimeError("Both CONTROL and TARGET need to be defined in the same step exactly once") raise RuntimeError("Both {} and {} need to be defined in the same step exactly once".format(
self.A, self.B
))
def compose(self, step, state): def compose(self, step, state):
# TODO: Hacky way to do CNOT
# Should generalize for a 2-Qubit gate
# _0.x(_0) * Matrix(I.m) + _1.x(_1) * Matrix(X.m) # _0.x(_0) * Matrix(I.m) + _1.x(_1) * Matrix(X.m)
outer_0, outer_1 = [], [] outer_0, outer_1 = [], []
for s in step: for s in step:
@ -555,11 +558,12 @@ Z = UnitaryOperator([[1, 0],
name="Z") name="Z")
# TODO: These are rotations that are specified commonly e.g. in # These are rotations that are specified commonly e.g. in
# https://www.quantum-inspire.com/kbase/rotation-operators/ # https://www.quantum-inspire.com/kbase/rotation-operators/
# http://www.vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf # http://www.vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf
# and elsewhere DO NOT equate X, Y and Z for theta=np.pi # and elsewhere DO NOT equate X, Y and Z for theta=np.pi
# ?????????????????????????????????????????????????????? # However - they are correct up to a global phase which is all that matters for measurement purposes
#
def Rx(theta): def Rx(theta):
return UnitaryOperator([[np.cos(theta / 2), -1j * np.sin(theta / 2)], return UnitaryOperator([[np.cos(theta / 2), -1j * np.sin(theta / 2)],
@ -578,11 +582,6 @@ def Rz(theta):
[0, np.power(np.e, 1j * theta / 2)]], [0, np.power(np.e, 1j * theta / 2)]],
name="Rz") name="Rz")
# def unitary(alpha, vector:Vector, theta):
# return np.exp(1j * alpha)
H = UnitaryOperator([[1 / np.sqrt(2), 1 / np.sqrt(2)], H = UnitaryOperator([[1 / np.sqrt(2), 1 / np.sqrt(2)],
[1 / np.sqrt(2), -1 / np.sqrt(2)], ], [1 / np.sqrt(2), -1 / np.sqrt(2)], ],
name="H") name="H")
@ -591,16 +590,7 @@ CNOT = TwoQubitOperator([[1, 0, 0, 0],
[0, 1, 0, 0], [0, 1, 0, 0],
[0, 0, 0, 1], [0, 0, 0, 1],
[0, 0, 1, 0], ], [0, 0, 1, 0], ],
TwoQubitPartial("C"), C_partial, x_partial, I, X)
TwoQubitPartial("x"),
I,
X)
C, x = CNOT.A, CNOT.B
# TODO: End Hacky way to define 2-qbit gate
###########################################################
def assert_raises(exception, msg, callable, *args, **kwargs): def assert_raises(exception, msg, callable, *args, **kwargs):
@ -664,7 +654,7 @@ class MeasurementOpeartor(HermitianOperator):
def get_prob(self, state: State): def get_prob(self, state: State):
state_ct = state.conjugate_transpose() state_ct = state.conjugate_transpose()
return np.asscalar(state_ct.m.dot(self.m.dot(state.m))) return state_ct.m.dot(self.m.dot(state.m)).item()
def test_measurement_ops(): def test_measurement_ops():
@ -939,24 +929,12 @@ class QuantumCircuit(object):
self.add_row(row_data) self.add_row(row_data)
def compose_quantum_state(self, step): def compose_quantum_state(self, step):
if C in step or x in step: partials = [op for op in step if isinstance(op, TwoQubitPartial)]
if not (step.count(C) == 1 and step.count(x) == 1): # TODO: No more than 1 TwoQubitGate **OR** UnitaryOperator can be used in a step
raise RuntimeError("Both CONTROL and TARGET need to be defined in the same step exactly once") for partial in partials:
# TODO: Hacky way to do CNOT two_qubit_op = partial.operator
# Should generalize for a 2-Qubit gate two_qubit_op.verify_step()
# _0.x(_0) * Matrix(I.m) + _1.x(_1) * Matrix(X.m) return two_qubit_op.compose(step)
outer_0, outer_1 = [], []
for s in step:
if s == C:
outer_0.append(_0.x(_0))
outer_1.append(_1.x(_1))
elif s == x:
outer_0.append(Matrix(I.m))
outer_1.append(Matrix(X.m))
else:
outer_0.append(Matrix(s.m))
outer_1.append(Matrix(s.m))
return reduce((lambda x, y: x * y), outer_0) + reduce((lambda x, y: x * y), outer_1)
return reduce((lambda x, y: x * y), step) return reduce((lambda x, y: x * y), step)
def step(self): def step(self):
@ -1077,9 +1055,9 @@ class QuantumProcessor(object):
def test_quantum_processor(): def test_quantum_processor():
# Produce Bell state between 0 and 2 qubit # Produce Bell state between 0 and 2 qubit
qc = QuantumCircuit(3) qc = QuantumCircuit(3)
qc.add_row([H, C]) qc.add_row([H, C_partial])
qc.add_row([_, _]) qc.add_row([_, _])
qc.add_row([_, x]) qc.add_row([_, x_partial])
qc.print() qc.print()
qp = QuantumProcessor(qc) qp = QuantumProcessor(qc)
qp.get_sample(100) qp.get_sample(100)