implemented flipping multiqubit gates

This commit is contained in:
Daniel Tsvetkov 2020-03-29 08:48:35 +02:00
parent 3e86010f7a
commit 92ccea6469

22
lib.py
View File

@ -624,7 +624,7 @@ class UnitaryOperator(LinearTransformation, UnitaryMatrix):
def operator_func(self, other, which_qbit=None): def operator_func(self, other, which_qbit=None):
this_cols, other_rows = np.shape(self.m)[1], np.shape(other.m)[0] this_cols, other_rows = np.shape(self.m)[1], np.shape(other.m)[0]
if this_cols == other_rows: if this_cols == other_rows and which_qbit is None:
return State(np.dot(self.m, other.m)) return State(np.dot(self.m, other.m))
if which_qbit is None: if which_qbit is None:
raise Exception("Operating dim-{} operator on a dim-{} state. " raise Exception("Operating dim-{} operator on a dim-{} state. "
@ -640,29 +640,30 @@ class UnitaryOperator(LinearTransformation, UnitaryMatrix):
new_m = np.prod(extended_m).m new_m = np.prod(extended_m).m
elif type(which_qbit) is list: elif type(which_qbit) is list:
# single or multiple qubit-gate # single or multiple qubit-gate
assert 1 <= len(which_qbit) < total_qbits assert 1 <= len(which_qbit) <= total_qbits
assert len(which_qbit) == len(self.partials) assert len(which_qbit) == len(self.partials)
assert all([q < total_qbits for q in which_qbit]) assert all([q < total_qbits for q in which_qbit])
this_gate_len = 2 ** (len(self.partials) - 1) this_gate_len = 2 ** (len(self.partials) - 1)
bins = generate_bins(this_gate_len) bins = generate_bins(this_gate_len)
extended_m, next_partial = [[] for _ in bins], 0 extended_m, next_control = [[] for _ in bins], 0
partial_mapping = dict(zip(which_qbit, self.partials))
for qbit in range(total_qbits): for qbit in range(total_qbits):
if qbit not in which_qbit: if qbit not in partial_mapping:
for i in range(this_gate_len): for i in range(this_gate_len):
extended_m[i].append(I) extended_m[i].append(I)
else: else:
this_partial = self.partials[next_partial] this_partial = partial_mapping[qbit]
# TODO: This works only with C_partial :((( # TODO: This works only with C_partial :(((
if this_partial == C_partial: if this_partial == C_partial:
for i in range(this_gate_len): for i in range(this_gate_len):
bin_dig = bins[i][next_partial] bin_dig = bins[i][next_control]
extended_m[i].append( extended_m[i].append(
s("|" + bin_dig + "><" + bin_dig + "|")) s("|" + bin_dig + "><" + bin_dig + "|"))
next_control += 1
else: else:
for i in range(this_gate_len - 1): for i in range(this_gate_len - 1):
extended_m[i].append(I) extended_m[i].append(I)
extended_m[-1].append(this_partial) extended_m[-1].append(this_partial)
next_partial += 1
new_m = sum([np.prod(e).m for e in extended_m]) new_m = sum([np.prod(e).m for e in extended_m])
else: else:
raise Exception( raise Exception(
@ -1019,6 +1020,13 @@ def test_partials():
"which_qubit to operate on", "which_qubit to operate on",
CNOT.on, s("|100>")) CNOT.on, s("|100>"))
# Test flipped CNOT
assert CNOT.on(s("|01>"), which_qbit=[1, 0]) == s("|11>")
assert CNOT.on(s("|001>"), which_qbit=[2, 0]) == s("|101>")
# Test SWAP via 3 successive CNOTs, the second is flipped
assert CNOT.on(CNOT.on(CNOT.on(s("|10>")), which_qbit=[1, 0])) == s("|01>")
# apply on 0, 1 of 3qbit state # apply on 0, 1 of 3qbit state
assert CNOT.on(s("|000>"), which_qbit=[0, 1]) == s("|000>") assert CNOT.on(s("|000>"), which_qbit=[0, 1]) == s("|000>")
assert CNOT.on(s("|100>"), which_qbit=[0, 1]) == s("|110>") assert CNOT.on(s("|100>"), which_qbit=[0, 1]) == s("|110>")