def test_add_qubit(self): s = StabilizerState() self.assertEqual(s.num_qubits, 0) z0 = StabilizerState([[0, 1]]) s.add_qubit() self.assertTrue(s == z0)
def test_cnot(self): num1 = self.eng.add_fresh_qubit() num2 = self.eng.add_fresh_qubit() self.eng.apply_H(num1) self.eng.apply_CNOT(num1, num2) state, _ = self.eng.get_register_RI() self.assertTrue(StabilizerState(state) == StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]))
def __init__(self, node, num, maxQubits=10): """ Initialize the simple engine. If no number is given for maxQubits, the assumption will be 10. """ super().__init__(node=node, num=num, maxQubits=maxQubits) self.qubitReg = StabilizerState()
def test_add_qubit_H(self): new_state = [[1, 0]] num = self.eng.add_qubit(new_state) self.assertEqual(num, 0) self.assertEqual(self.eng.activeQubits, 1) self.assertEqual(len(self.eng.qubitReg), 1) state, _ = self.eng.get_register_RI() self.assertEqual(StabilizerState(state), StabilizerState(new_state))
def test_absorb_parts_other_empty(self): num = self.eng.add_fresh_qubit() self.eng.apply_H(num) eng2 = stabilizerEngine("Alice", 0) self.eng.absorb_parts(*eng2.get_register_RI(), eng2.activeQubits) self.assertEqual(self.eng.activeQubits, 1) self.assertEqual(len(self.eng.qubitReg), 1) state, _ = self.eng.get_register_RI() self.assertTrue(StabilizerState(state) == StabilizerState([[1, 0]]))
def test_standard_form(self): s1 = StabilizerState([[1, 0, 0, 0], [0, 1, 0, 0]]) s2 = StabilizerState([[1, 0, 0, 0], [1, 1, 0, 0]]) s3 = StabilizerState([[1, 0, 0, 0, 1], [1, 1, 0, 0, 0]]) s4 = StabilizerState([[1, 0, 0, 0, 1], [0, 1, 0, 0, 1]]) self.assertTrue(s1 == s2) self.assertFalse(s1 == s3) self.assertTrue(s3 == s4)
def test_absorb_parts(self): self.eng.add_fresh_qubit() eng2 = stabilizerEngine("Alice", 0) eng2.add_fresh_qubit() self.eng.absorb_parts(*eng2.get_register_RI(), eng2.activeQubits) self.assertEqual(self.eng.activeQubits, 2) self.assertEqual(len(self.eng.qubitReg), 2) state, _ = self.eng.get_register_RI() self.assertTrue(StabilizerState(state) == StabilizerState([[0, 0, 1, 0], [0, 0, 0, 1]]))
def test_absorb_this_empty_H(self): eng2 = stabilizerEngine("Alice", 0) num = eng2.add_fresh_qubit() eng2.apply_H(num) self.eng.absorb(eng2) self.assertEqual(self.eng.activeQubits, 1) self.assertEqual(len(self.eng.qubitReg), 1) state, _ = self.eng.get_register_RI() self.assertTrue(StabilizerState(state) == StabilizerState([[1, 0]]))
def test_init_of_number_of_qubits(self): s = StabilizerState(1) z0 = StabilizerState([[0, 1]]) self.assertEqual(s.num_qubits, 1) self.assertTrue(s == z0) s = StabilizerState(2) self.assertEqual(s.num_qubits, 2) self.assertTrue(s == z0.tensor_product(z0))
def test_absorb_parts_EPR(self): eng2 = stabilizerEngine("Alice", 0) num1 = eng2.add_fresh_qubit() num2 = eng2.add_fresh_qubit() eng2.apply_H(num1) eng2.apply_CNOT(num1, num2) self.eng.absorb_parts(*eng2.get_register_RI(), eng2.activeQubits) self.assertEqual(self.eng.activeQubits, 2) self.assertEqual(len(self.eng.qubitReg), 2) state, _ = self.eng.get_register_RI() self.assertTrue(StabilizerState(state) == StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]))
def test_symplectic_check(self): StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) with self.assertRaises(ValueError): StabilizerState([[1, 0, 0, 0], [0, 0, 1, 0]]) with self.assertRaises(ValueError): StabilizerState([[1, 1, 0, 0], [0, 0, 1, 0]]) with self.assertRaises(ValueError): StabilizerState([[1, 1, 1, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 0, 0, 1, 0, 0]])
def remote_receive_one_qubit(self, virtualNum, cnot_direction=0): """ Recover the qubit from teleportation. Arguments a,b received measurement outcomes from Alice virtualNum number of the virtual qubit corresponding to the EPR pair received """ logging.debug("LOCAL %s: Getting reference to qubit number %d.", self.node.name, virtualNum) # Get a reference to our side of the EPR pair qA = yield self.virtRoot.callRemote("get_virtual_ref", virtualNum) # Create a fresh qubit q = yield self.virtRoot.callRemote("new_qubit_inreg", self.qReg) # Create the GHZ state by entangling the fresh qubit if cnot_direction == 0: yield qA.callRemote("apply_H") yield qA.callRemote("cnot_onto", q) else: yield q.callRemote("apply_H") yield q.callRemote("cnot_onto", qA) if simulaqron_settings.backend == "qutip": # Output state (realRho, imagRho) = yield self.virtRoot.callRemote("get_multiple_qubits", [qA, q]) rho = assemble_qubit(realRho, imagRho) expectedRho = [[0.5, 0, 0, 0.5], [0, 0, 0, 0], [0, 0, 0, 0], [0.5, 0, 0, 0.5]] correct = np.all(np.isclose(rho, expectedRho)) elif simulaqron_settings.backend == "projectq": (realvec, imagvec) = yield self.virtRoot.callRemote("get_register_RI", qA) state = [r + (1j * j) for r, j in zip(realvec, imagvec)] expectedState = [1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)] correct = np.all(np.isclose(state, expectedState)) elif simulaqron_settings.backend == "stabilizer": (array, _) = yield self.virtRoot.callRemote("get_register_RI", qA) state = StabilizerState(array) expectedState = StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) correct = state == expectedState else: ValueError("Unknown backend {}".format( simulaqron_settings.backend)) return bool(correct)
def alice(cls, qReg, virtRoot, myName, classicalNet, send_end): """ Code to execute for the local client node. Called if all connections are established. Arguments qReg quantum register (twisted object supporting remote method calls) virtRoot virtual quantum ndoe (twisted object supporting remote method calls) myName name of this node (string) classicalNet servers in the classical communication network (dictionary of hosts) """ logging.debug("LOCAL %s: Runing client side program.", myName) # Create a second register newReg = yield virtRoot.callRemote("add_register") # Create 2 qubits qA = yield virtRoot.callRemote("new_qubit_inreg", qReg) qB = yield virtRoot.callRemote("new_qubit_inreg", newReg) # Put qubits A and B in an EPR state yield qA.callRemote("apply_H") yield qA.callRemote("cnot_onto", qB) if simulaqron_settings.backend == "qutip": # Output state (realRho, imagRho) = yield virtRoot.callRemote("get_multiple_qubits", [qA, qB]) rho = assemble_qubit(realRho, imagRho) expectedRho = [[0.5, 0, 0, 0.5], [0, 0, 0, 0], [0, 0, 0, 0], [0.5, 0, 0, 0.5]] correct = np.all(np.isclose(rho, expectedRho)) elif simulaqron_settings.backend == "projectq": (realvec, imagvec, _, _, _) = yield virtRoot.callRemote("get_register", qA) state = [r + (1j * j) for r, j in zip(realvec, imagvec)] expectedState = [1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)] correct = np.all(np.isclose(state, expectedState)) elif simulaqron_settings.backend == "stabilizer": (array, _, _, _, _) = yield virtRoot.callRemote("get_register", qA) state = StabilizerState(array) expectedState = StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) correct = state == expectedState else: ValueError("Unknown backend {}".format( simulaqron_settings.backend)) send_end.send(correct) reactor.stop()
def test_correct_init(self): state = StabilizerState([[0, 1]]) self.assertAlmostEqual(state.num_qubits, 1) state = StabilizerState([[0, 1, 0]]) self.assertAlmostEqual(state.num_qubits, 1) state = StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) self.assertAlmostEqual(state.num_qubits, 2) state = StabilizerState([[1, 1, 0, 0, 0], [0, 0, 1, 1, 1]]) self.assertAlmostEqual(state.num_qubits, 2) self.assertTrue(state == StabilizerState(state))
def test_contains(self): tests = [ # stabilizer, expected ("XX", True), ("+1XX", True), ("-1XX", False), ("+1YY", False), ("-1YY", True), ("+1YI", False), ("IY", False), ] for stabilizer, expected in tests: with self.subTest(stabilizer=stabilizer, expected=expected): s = StabilizerState(["XX", "ZZ"]) output = s.contains(stabilizer) self.assertEqual(output, expected)
def test_absorb_this_empty_GHZ(self): n = 5 eng2 = stabilizerEngine("Alice", 0) qubits = [eng2.add_fresh_qubit() for _ in range(n)] eng2.apply_H(qubits[0]) for i in range(1, n): eng2.apply_CNOT(qubits[0], qubits[i]) self.eng.absorb(eng2) self.assertEqual(self.eng.activeQubits, n) self.assertEqual(len(self.eng.qubitReg), n) state, _ = self.eng.get_register_RI() ref = [1 / np.sqrt(2)] + [0] * (2 ** n - 2) + [1 / np.sqrt(2)] ref = [[1] * n + [0] * n] for i in range(n - 1): ref += [[0] * n + [0] * i + [1] * 2 + [0] * (n - i - 2)] self.assertTrue(StabilizerState(state) == StabilizerState(ref))
def test_Pauli_phase_tracking(self): S = StabilizerState() self.assertFalse(S.Pauli_phase_tracking([False, False], [False, False])) self.assertFalse(S.Pauli_phase_tracking([True, True], [True, True])) self.assertFalse(S.Pauli_phase_tracking([True, False], [True, False])) self.assertFalse(S.Pauli_phase_tracking([False, True], [False, True])) self.assertTrue(S.Pauli_phase_tracking([True, True], [True, False])) self.assertTrue(S.Pauli_phase_tracking([False, True], [True, True])) self.assertTrue(S.Pauli_phase_tracking([True, False], [False, True])) self.assertEqual(S.Pauli_phase_tracking([True, False], [True, True]), S.Pauli_phase_tracking([True, True], [False, True])) self.assertEqual(S.Pauli_phase_tracking([False, True], [True, False]), S.Pauli_phase_tracking([True, True], [False, True]))
def test_measure_eigenstate(self): tests = [ # stabilizers, qubit, expected (["ZI", "IZ"], 0, 0), (["-1ZI", "IZ"], 0, 1), (["ZI", "ZZ"], 0, 0), (["IZ", "-1ZZ"], 0, 1), (["IZ", "-1ZI"], 0, 1), (["+1XIIII", "+1IXIII", "+1IIXII", "-1IIIZI", "+1IIIZZ"], 4, 1), ] for stabilizers, qubit, expected in tests: with self.subTest(stabilizers=stabilizers, qubit=qubit, expected=expected): s = StabilizerState(stabilizers) output = s.measure(qubit) self.assertEqual(output, expected)
def test_correlations(self): tests = [ # stabilizers ["ZI", "IZ"], ["ZZ", "XX"], ["ZX", "XZ"], ["XXX", "ZZI", "IZZ"], ["XIII", "IXII", "IIXI", "IIIX"], ["XZII", "ZXZI", "IZXZ", "IIZX"], # line graph ["XZIZ", "ZXZI", "IZXZ", "ZIZX"], # cycle graph ["XZZZ", "ZXZZ", "ZZXZ", "ZZZX"], # complete graph ["XZZZ", "ZXII", "ZIXI", "ZIIX"], # star graph ] for stabilizers in tests: for stabilizer in stabilizers: for _ in range(10): with self.subTest(stabilizers=stabilizers, stabilizer=stabilizer): s = StabilizerState(stabilizers) outcomes = [] qubit = 0 for pauli in stabilizer: if pauli == 'X': s.apply_H(qubit) elif pauli == 'Y': s.apply_K(qubit) elif pauli == 'Z': pass else: qubit += 1 continue outcomes.append(s.measure(qubit)) self.assertEqual(sum(outcomes) % 2, 0)
def test_GHZ(self): n = 5 for _ in range(20): GHZ = StabilizerState(n) GHZ.apply_H(0) for i in range(1, n): GHZ.apply_CNOT(0, i) outcomes = [GHZ.measure(0) for _ in range(n)] self.assertNotIn(False, [outcomes[0] == outcomes[i] for i in range(1, n)])
def got_both(self): """ Recover the qubit from Bob. We should now have a tripartite GHZ state Arguments virtualNum number of the virtual qubit corresponding to the EPR pair received """ logging.debug("LOCAL %s: Got both qubits from Alice and Bob.", self.node.name) # We'll test an operation that will cause a merge of the two remote registers yield self.q1.callRemote("apply_H") yield self.q1.callRemote("cnot_onto", self.q2) if simulaqron_settings.backend == "qutip": # Output state (realRho, imagRho) = yield self.virtRoot.callRemote("get_multiple_qubits", [self.q1, self.q2]) rho = assemble_qubit(realRho, imagRho) expectedRho = [[0.5, 0, 0, 0.5], [0, 0, 0, 0], [0, 0, 0, 0], [0.5, 0, 0, 0.5]] correct = np.all(np.isclose(rho, expectedRho)) elif simulaqron_settings.backend == "projectq": (realvec, imagvec) = yield self.virtRoot.callRemote("get_register_RI", self.q1) state = [r + (1j * j) for r, j in zip(realvec, imagvec)] expectedState = [1 / np.sqrt(2), 0, 0, 1 / np.sqrt(2)] correct = np.all(np.isclose(state, expectedState)) elif simulaqron_settings.backend == "stabilizer": (array, _) = yield self.virtRoot.callRemote("get_register_RI", self.q1) state = StabilizerState(array) expectedState = StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) correct = state == expectedState else: ValueError("Unknown backend {}".format( simulaqron_settings.backend)) return bool(correct)
def test_reduce_when_measuring(self): tests = [ # stabilizers ["ZI", "IZ"], ["ZZ", "XX"], ["ZX", "XZ"], ["XXX", "ZZI", "IZZ"], ["XIII", "IXII", "IIXI", "IIIX"], ["XZII", "ZXZI", "IZXZ", "IIZX"], # line graph ["XZIZ", "ZXZI", "IZXZ", "ZIZX"], # cycle graph ["XZZZ", "ZXZZ", "ZZXZ", "ZZZX"], # complete graph ["XZZZ", "ZXII", "ZIXI", "ZIIX"], # star graph ] for stabilizers in tests: with self.subTest(stabilizers=stabilizers): state = StabilizerState(stabilizers) n = len(state) for i in range(n): state.measure(0) self.assertEqual(len(state), n - i - 1)
def test_standard_form(self): tests = [ # stabilizers ["ZI", "IZ"], ["ZZ", "XX"], ["ZX", "XZ"], ["XXX", "ZZI", "IZZ"], ["XIII", "IXII", "IIXI", "IIIX"], ["XZII", "ZXZI", "IZXZ", "IIZX"], # line graph ["XZIZ", "ZXZI", "IZXZ", "ZIZX"], # cycle graph ["XZZZ", "ZXZZ", "ZZXZ", "ZZZX"], # complete graph ["XZZZ", "ZXII", "ZIXI", "ZIIX"], # star graph ] for stabilizers in tests: with self.subTest(stabilizers=stabilizers): state = StabilizerState(stabilizers) state.put_in_standard_form() # Check that there are no X or Y in the first column except the first row for row in state._group[1:, :]: self.assertFalse(row[0])
def test_gaussian_elimination(self): S = StabilizerState(["XZZ", "YIX", "IXX"]) S.put_in_standard_form() self.assertTrue( np.array_equal( S.to_array(), StabilizerState(["+1XZZ", "-1ZYZ", "-1ZZY"]).to_array()))
def absorb_parts(self, R, I, activeQ): """ Absorb the qubits, given in pieces Arguments: R The array describing the stabilizer state (from StabilizerState.to_array) I Unused activeQ active number of qubits """ # Check whether there is space newNum = self.activeQubits + activeQ if newNum > self.maxQubits: raise quantumError( "Cannot merge: qubits exceed the maximum available.\n") self.qubitReg = self.qubitReg.tensor_product(StabilizerState(R))
def add_qubit(self, newQubit): """ Add new qubit in the state described by the array containing the generators of the stabilizer group. This should be in the form required by the StabilizerState class. """ # Create the qubit try: qubit = StabilizerState(newQubit) except Exception: raise ValueError( "'newQubits' was not in the correct form to be given as an argument to StabilizerState" ) num = self.activeQubits self.qubitReg = self.qubitReg.tensor_product(qubit) return num
def test_eq(self): state1 = StabilizerState([[0, 1]]) state2 = StabilizerState([[0, 1]]) state3 = StabilizerState([[0, 1, 0]]) state4 = StabilizerState([[0, 1, 1]]) state5 = StabilizerState([[1, 1, 0]]) state6 = StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) self.assertTrue(state1 == state1) self.assertTrue(state1 == state2) self.assertTrue(state1 == state3) self.assertFalse(state1 == state4) self.assertFalse(state1 == state5) self.assertFalse(state5 == state6)
def test_tensor_product(self): s1 = StabilizerState([[0, 1]]) # The state |0> s2 = StabilizerState([[0, 1]]) # The state |0> s3 = s1 * s2 # This is then the state |00> s4 = StabilizerState([[0, 0, 1, 0], [0, 0, 0, 1]]) self.assertEqual(s3.num_qubits, 2) self.assertTrue(s3 == s4) s1 = StabilizerState([[0, 1]]) # The state |0> s2 = StabilizerState([[0, 1, 1]]) # The state |1> s3 = s1 * s2 # This is then the state |01> s4 = StabilizerState([[0, 0, 1, 0, 0], [0, 0, 0, 1, 1]]) self.assertEqual(s3.num_qubits, 2) self.assertTrue(s3 == s4)
def remote_recover_teleport(self, a, b, virtualNum): """ Recover the qubit from teleportation. Arguments a,b received measurement outcomes from Alice virtualNum number of the virtual qubit corresponding to the EPR pair received """ logging.debug("LOCAL %s: Getting reference to qubit number %d.", self.node.name, virtualNum) eprB = yield self.virtRoot.callRemote("get_virtual_ref", virtualNum) # Apply the desired correction info logging.debug("LOCAL %s: Correction info is a=%d, b=%d.", self.node.name, a, b) if b == 1: yield eprB.callRemote("apply_X") if a == 1: yield eprB.callRemote("apply_Z") # Just print the qubit we received if simulaqron_settings.backend == "qutip": print("here") (realRho, imagRho) = yield eprB.callRemote("get_qubit") state = np.array(assemble_qubit(realRho, imagRho), dtype=complex) elif simulaqron_settings.backend == "projectq": realvec, imagvec = yield self.virtRoot.callRemote( "get_register_RI", eprB) state = [r + (1j * j) for r, j in zip(realvec, imagvec)] elif simulaqron_settings.backend == "stabilizer": array, _, = yield self.virtRoot.callRemote("get_register_RI", eprB) state = StabilizerState(array) else: ValueError("Unknown backend {}".format( simulaqron_settings.backend)) print("Qubit is:\n{}".format(state))
def test_list_of_str_init(self): phip = StabilizerState([[1, 1, 0, 0], [0, 0, 1, 1]]) phim = StabilizerState([[1, 1, 0, 0, 0], [0, 0, 1, 1, 1]]) data = ["XX", "ZZ"] s1 = StabilizerState(data) self.assertTrue(s1 == phip) data = ["+1XX", "+1ZZ"] s1 = StabilizerState(data) self.assertTrue(s1 == phip) data = ["+1XX", "-1ZZ"] s1 = StabilizerState(data) self.assertTrue(s1 == phim) # Test faulty input data = ["XX", "-1ZZ"] with self.assertRaises(ValueError): StabilizerState(data) data = ["XX", "ZZZ"] with self.assertRaises(ValueError): StabilizerState(data)