def test_raise_compose_different_dim(self): """Test composing incompatible errors raises exception""" error0 = QuantumError([np.diag([1, 1, 1, -1])]) # 2-qubit coherent error error1 = QuantumError([np.diag([1, -1])]) # 1-qubit coherent error self.assertRaises(NoiseError, lambda: error0.compose(error1)) self.assertRaises(NoiseError, lambda: error1.compose(error0))
def test_reset_2_qubit(self): # approximating amplitude damping using relaxation operators gamma = 0.23 p = (gamma - numpy.sqrt(1 - gamma) + 1) / 2 q = 0 A0 = [[1, 0], [0, numpy.sqrt(1 - gamma)]] A1 = [[0, numpy.sqrt(gamma)], [0, 0]] error_1 = QuantumError([([{'name': 'kraus', 'qubits': [0], 'params': [A0, A1]}, {'name': 'id', 'qubits': [1]} ], 1)]) error_2 = QuantumError([([{'name': 'kraus', 'qubits': [1], 'params': [A0, A1]}, {'name': 'id', 'qubits': [0]} ], 1)]) expected_results_1 = QuantumError([ ([{'name': 'id', 'qubits': [0]}, {'name': 'id', 'qubits': [1]}], 1-p), ([{'name': 'reset', 'qubits': [0]}, {'name': 'id', 'qubits': [1]}],p), ]) expected_results_2 = QuantumError([ ([{'name': 'id', 'qubits': [1]}, {'name': 'id', 'qubits': [0]}], 1 - p), ([{'name': 'reset', 'qubits': [1]}, {'name': 'id', 'qubits': [0]}], p), ]) results_1 = approximate_quantum_error(error_1, operator_string="reset") results_2 = approximate_quantum_error(error_2, operator_string="reset") self.assertErrorsAlmostEqual(results_1, expected_results_1) self.assertErrorsAlmostEqual(results_2, expected_results_2)
def test_dot_both_kraus(self): """Test dot of two kraus errors""" a_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) a_1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) b_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) b_1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) # Use quantum channels for reference target = SuperOp(Kraus([b_0, b_1]).compose(Kraus([a_0, a_1]))) # dot method error = QuantumError([a_0, a_1]).dot(QuantumError([b_0, b_1])) kraus, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(kraus[0]['name'], 'kraus') self.assertEqual(kraus[0]['qubits'], [0]) error_superop = SuperOp(Kraus(kraus[0]['params'])) self.assertEqual(target, error_superop, msg="Incorrect kraus dot method") # * method error = QuantumError([a_0, a_1]) * QuantumError([b_0, b_1]) kraus, prob = error.error_term(0) self.assertEqual(prob, 1) self.assertEqual(kraus[0]['name'], 'kraus') self.assertEqual(kraus[0]['qubits'], [0]) error_superop = SuperOp(Kraus(kraus[0]['params'])) self.assertEqual(target, error_superop, msg="Incorrect kraus dot method")
def test_equal(self): """Test two quantum errors are equal""" Ai = np.sqrt(0.25) * standard_gate_unitary('id') Ax = np.sqrt(0.25) * standard_gate_unitary('x') Ay = np.sqrt(0.25) * standard_gate_unitary('y') Az = np.sqrt(0.25) * standard_gate_unitary('z') error1 = QuantumError([Ai, Ax, Ay, Az], standard_gates=True) error2 = QuantumError([Ai, Ax, Ay, Az], standard_gates=False) self.assertEqual(error1, error2)
def test_to_quantumchannel_kraus(self): """Test to_quantumchannel for Kraus inputs.""" a_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) a_1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) b_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) b_1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) target = SuperOp(Kraus([a_0, a_1])).tensor(SuperOp(Kraus([b_0, b_1]))) error = QuantumError([a_0, a_1]).tensor(QuantumError([b_0, b_1])) self.assertEqual(target, error.to_quantumchannel())
def test_equal(self): """Test two quantum errors are equal""" a_i = np.sqrt(0.25) * standard_gate_unitary('id') a_x = np.sqrt(0.25) * standard_gate_unitary('x') a_y = np.sqrt(0.25) * standard_gate_unitary('y') a_z = np.sqrt(0.25) * standard_gate_unitary('z') error1 = QuantumError([a_i, a_x, a_y, a_z], standard_gates=True) error2 = QuantumError([a_i, a_x, a_y, a_z], standard_gates=False) self.assertEqual(error1, error2)
def test_to_channel_kraus(self): """Test to_channel for Kraus inputs.""" A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) A1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) B0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) B1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) target = SuperOp(Kraus([A0, A1])).tensor(SuperOp(Kraus([B0, B1]))) error = QuantumError([A0, A1]).tensor(QuantumError([B0, B1])) self.assertEqual(target, error.to_channel())
def test_dot_both_qobj(self): """Test dot of two circuit errors""" unitaries0 = [standard_gate_unitary('id'), standard_gate_unitary('z')] probs0 = [0.9, 0.1] unitaries1 = [standard_gate_unitary('x'), standard_gate_unitary('y')] probs1 = [0.6, 0.4] error0 = QuantumError([ np.sqrt(probs0[0]) * unitaries0[0], np.sqrt(probs0[1]) * unitaries0[1] ], standard_gates=True) error1 = QuantumError([ np.sqrt(probs1[0]) * unitaries1[0], np.sqrt(probs1[1]) * unitaries1[1] ], standard_gates=True) error = error1.dot(error0) # Kronecker product probabilities target_probs = [ probs1[0] * probs0[0], probs1[0] * probs0[1], probs1[1] * probs0[0], probs1[1] * probs0[1] ] # Target circuits target_circs = [[{ 'name': 'x', 'qubits': [0] }], [{ 'name': 'y', 'qubits': [0] }], [{ 'name': 'z', 'qubits': [0] }, { 'name': 'x', 'qubits': [0] }], [{ 'name': 'z', 'qubits': [0] }, { 'name': 'y', 'qubits': [0] }]] for j in range(4): circ, prob = error.error_term(j) # Remove prob from target if it is found # later we will check that target_probs is empty so all # the required ones have been removed self.remove_if_found(prob, target_probs) self.remove_if_found(circ, target_circs) # Check we had all the correct target probs and unitaries # by seeing if these lists are empty # Note that this doesn't actually check that the correct # prob was assigned to the correct unitary. self.assertEqual(target_probs, [], msg="Incorrect compose probabilities") self.assertEqual(target_circs, [], msg="Incorrect compose circuits")
def old_approximate_quantum_error(error, *, operator_string=None, operator_dict=None, operator_list=None): if not isinstance(error, QuantumError): error = QuantumError(error) if error.number_of_qubits > 2: raise NoiseError( "Only 1-qubit and 2-qubit noises can be converted, {}-qubit " "noise found in model".format(error.number_of_qubits)) error_kraus_operators = Kraus(error.to_quantumchannel()).data transformer = NoiseTransformer() if operator_string is not None: no_info_error = "No information about noise type {}".format( operator_string) operator_string = operator_string.lower() if operator_string not in transformer.named_operators.keys(): raise RuntimeError(no_info_error) operator_lists = transformer.named_operators[operator_string] if len(operator_lists) < error.number_of_qubits: raise RuntimeError( no_info_error + " for {} qubits".format(error.number_of_qubits)) operator_dict = operator_lists[error.number_of_qubits - 1] if operator_dict is not None: _, operator_list = zip(*operator_dict.items()) if operator_list is not None: op_matrix_list = [ transformer.operator_matrix(operator) for operator in operator_list ] probabilities = transformer.transform_by_operator_list( op_matrix_list, error_kraus_operators) identity_prob = numpy.round(1 - sum(probabilities), 9) if identity_prob < 0 or identity_prob > 1: raise RuntimeError( "Channel probabilities sum to {}".format(1 - identity_prob)) quantum_error_spec = [([{ 'name': 'id', 'qubits': [0] }], identity_prob)] op_circuit_list = [ transformer.operator_circuit(operator) for operator in operator_list ] for (operator, probability) in zip(op_circuit_list, probabilities): quantum_error_spec.append((operator, probability)) return QuantumError(quantum_error_spec) raise NoiseError( "Quantum error approximation failed - no approximating operators detected" )
def test_compose_both_kraus(self): """Test composition of two kraus errors""" A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) A1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) B0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) B1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) # Use quantum channels for reference target = SuperOp(Kraus([A0, A1]).compose(Kraus([B0, B1]))) error = QuantumError([A0, A1]).compose(QuantumError([B0, B1])) kraus, p = error.error_term(0) self.assertEqual(p, 1) self.assertEqual(kraus[0]['name'], 'kraus') self.assertEqual(kraus[0]['qubits'], [0]) error_superop = SuperOp(Kraus(kraus[0]['params'])) self.assertEqual(target, error_superop, msg="Incorrect compose kraus")
def test_dot_both_unitary(self): """Test dot of two unitary errors.""" unitaries0 = [standard_gate_unitary('z'), standard_gate_unitary('s')] probs0 = [0.9, 0.1] unitaries1 = [standard_gate_unitary('x'), standard_gate_unitary('y')] probs1 = [0.6, 0.4] error0 = QuantumError([ np.sqrt(probs0[0]) * unitaries0[0], np.sqrt(probs0[1]) * unitaries0[1] ], standard_gates=False) error1 = QuantumError([ np.sqrt(probs1[0]) * unitaries1[0], np.sqrt(probs1[1]) * unitaries1[1] ], standard_gates=False) error = error1.dot(error0) # Kronecker product unitaries target_unitaries = [ np.dot(unitaries1[0], unitaries0[0]), np.dot(unitaries1[0], unitaries0[1]), np.dot(unitaries1[1], unitaries0[0]), np.dot(unitaries1[1], unitaries0[1]) ] # Kronecker product probabilities target_probs = [ probs1[0] * probs0[0], probs1[0] * probs0[1], probs1[1] * probs0[0], probs1[1] * probs0[1] ] for j in range(4): circ, prob = error.error_term(j) unitary = circ[0]['params'][0] self.assertEqual(circ[0]['name'], 'unitary') self.assertEqual(circ[0]['qubits'], [0]) # Remove prob from target if it is found # later we will check that target_probs is empty so all # the required ones have been removed self.remove_if_found(prob, target_probs) self.remove_if_found(unitary, target_unitaries) # Check we had all the correct target probs and unitaries # by seeing if these lists are empty # Note that this doesn't actually check that the correct # prob was assigned to the correct unitary. self.assertEqual(target_probs, [], msg="Incorrect compose probabilities") self.assertEqual(target_unitaries, [], msg="Incorrect compose unitaries")
def test_compose_both_kraus(self): """Test composition of two kraus errors""" A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]]) A1 = np.array([[0, 0], [0, np.sqrt(0.3)]]) B0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]]) B1 = np.array([[0, 0], [0, np.sqrt(0.5)]]) error = QuantumError([A0, A1]).compose(QuantumError([B0, B1])) kraus, p = error.error_term(0) targets = [np.dot(B0, A0), np.dot(B0, A1), np.dot(B1, A0), np.dot(B1, A1)] self.assertEqual(p, 1) self.assertEqual(kraus[0]['name'], 'kraus') self.assertEqual(kraus[0]['qubits'], [0]) for op in kraus[0]['params']: self.remove_if_found(op, targets) self.assertEqual(targets, [], msg="Incorrect compose kraus")
def test_reset_error_all_qubit_100percent(self): """Test 100% precent reset error on all qubits""" # Test circuit: ideal outcome "11" qr = QuantumRegister(2, 'qr') cr = ClassicalRegister(2, 'cr') circuit = QuantumCircuit(qr, cr) circuit.x(qr) circuit.measure(qr, cr) backend = QasmSimulator() noise_circs = [[{ "name": "reset", "qubits": [0] }], [{ "name": "id", "qubits": [0] }]] # 100% reset noise on all qubit "u3". noise_probs = [1, 0] error = QuantumError(zip(noise_circs, noise_probs)) noise_model = NoiseModel() noise_model.add_all_qubit_quantum_error(error, "u3") shots = 100 # target = {'00': shots} target = {'0x0': shots} qobj = compile([circuit], backend, shots=shots, basis_gates=noise_model.basis_gates) result = backend.run(qobj, noise_model=noise_model).result() self.is_completed(result) self.compare_counts(result, [circuit], [target], delta=0)
def test_approx_random_mixed_unitary_channel_2q(self): # run without raising any error noise1 = UnitaryGate(random_unitary(4, seed=123)) noise2 = UnitaryGate(random_unitary(4, seed=456)) noise = QuantumError([(noise1, 0.7), (noise2, 0.3)]) for opstr in ['pauli', 'reset']: approximate_quantum_error(noise, operator_string=opstr)
def test_reset_error_specific_qubit_50percent(self): """Test 50% perecent reset error on qubit-0""" # Test circuit: ideal outcome "11" qr = QuantumRegister(2, 'qr') cr = ClassicalRegister(2, 'cr') circuit = QuantumCircuit(qr, cr) circuit.x(qr) circuit.measure(qr, cr) backend = QasmSimulator() noise_circs = [[{ "name": "reset", "qubits": [0] }], [{ "name": "id", "qubits": [0] }]] # 50% reset noise on qubit-0 "u3" only. noise_probs = [0.5, 0.5] error = QuantumError(zip(noise_circs, noise_probs)) noise_model = NoiseModel() noise_model.add_quantum_error(error, "u3", [0]) shots = 2000 target = {'0x2': shots / 2, '0x3': shots / 2} circuit = transpile(circuit, basis_gates=noise_model.basis_gates) qobj = assemble([circuit], backend, shots=shots) result = backend.run(qobj, noise_model=noise_model).result() self.is_completed(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots)
def test_reset_error_specific_qubit_25percent(self): """Test 25% percent reset error on qubit-1""" # Test circuit: ideal outcome "11" qr = QuantumRegister(2, 'qr') cr = ClassicalRegister(2, 'cr') circuit = QuantumCircuit(qr, cr) circuit.x(qr) circuit.measure(qr, cr) backend = QasmSimulator() noise_circs = [[{ "name": "reset", "qubits": [0] }], [{ "name": "id", "qubits": [0] }]] # 25% reset noise on qubit-1 "u3" only. noise_probs = [0.25, 0.75] error = QuantumError(zip(noise_circs, noise_probs)) noise_model = NoiseModel() noise_model.add_quantum_error(error, "u3", [1]) shots = 1000 # target = {'01': shots / 4, '11': 3 * shots / 4} target = {'0x1': shots / 4, '0x3': 3 * shots / 4} qobj = compile([circuit], backend, shots=shots, basis_gates=noise_model.basis_gates) result = backend.run(qobj, noise_model=noise_model).result() self.is_completed(result) self.compare_counts(result, [circuit], [target], delta=0.05 * shots)
def test_raise_probabilities_normalized_nonunitary_kraus(self): """Test exception is raised for non-unitary kraus probs greater than 1.""" a_0 = np.sqrt(0.9) * np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) a_1 = np.sqrt(0.2) * np.array([[0, np.sqrt(0.3)], [0, 0]], dtype=complex) self.assertRaises(NoiseError, lambda: QuantumError([a_0, a_1]))
def test_raise_probabilities_negative(self): """Test exception is raised for negative probabilities.""" noise_ops = [([{ "name": "id", "qubits": [0] }], 1.1), ([{ "name": "x", "qubits": [0] }], -0.1)] self.assertRaises(NoiseError, lambda: QuantumError(noise_ops))
def test_raise_probabilities_normalized_qobj(self): """Test exception is raised for qobj probabilities greater than 1.""" noise_ops = [([{ "name": "id", "qubits": [0] }], 0.9), ([{ "name": "x", "qubits": [0] }], 0.2)] self.assertRaises(NoiseError, lambda: QuantumError(noise_ops))
def test_expand_both_kraus(self): """Test expand of two kraus errors""" A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) A1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex) B0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex) B1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex) error = QuantumError([A0, A1]).expand(QuantumError([B0, B1])) kraus, p = error.error_term(0) targets = [ np.kron(B0, A0), np.kron(B1, A0), np.kron(B0, A1), np.kron(B1, A1) ] self.assertEqual(p, 1) self.assertEqual(kraus[0]['name'], 'kraus') self.assertEqual(kraus[0]['qubits'], [0, 1]) for op in kraus[0]['params']: self.remove_if_found(op, targets) self.assertEqual(targets, [], msg="Incorrect expand kraus")
def test_pauli_conversion_standard_gates(self): """Test conversion of Pauli channel kraus to gates""" Ai = np.sqrt(0.25) * standard_gate_unitary('id') Ax = np.sqrt(0.25) * standard_gate_unitary('x') Ay = np.sqrt(0.25) * standard_gate_unitary('y') Az = np.sqrt(0.25) * standard_gate_unitary('z') error_dict = QuantumError([Ai, Ax, Ay, Az], standard_gates=True).as_dict() self.assertEqual(error_dict['type'], 'qerror') self.assertAlmostEqual(np.linalg.norm(np.array(4 * [0.25]) - np.array(error_dict['probabilities'])), 0.0) for instr in error_dict['instructions']: self.assertEqual(len(instr), 1) self.assertIn(instr[0]['name'], ['x', 'y', 'z', 'id']) self.assertEqual(instr[0]['qubits'], [0])
def test_reset_2_qubit(self): # approximating amplitude damping using relaxation operators gamma = 0.23 p = (gamma - numpy.sqrt(1 - gamma) + 1) / 2 A0 = [[1, 0], [0, numpy.sqrt(1 - gamma)]] A1 = [[0, numpy.sqrt(gamma)], [0, 0]] error_1 = QuantumError([([(Kraus([A0, A1]), [0]), (IGate(), [1])], 1)]) error_2 = QuantumError([([(Kraus([A0, A1]), [1]), (IGate(), [0])], 1)]) expected_results_1 = QuantumError([([(IGate(), [0]), (IGate(), [1])], 1 - p), ([(Reset(), [0]), (IGate(), [1])], p)]) expected_results_2 = QuantumError([([(IGate(), [1]), (IGate(), [0])], 1 - p), ([(Reset(), [1]), (IGate(), [0])], p)]) results_1 = approximate_quantum_error(error_1, operator_string="reset") results_2 = approximate_quantum_error(error_2, operator_string="reset") self.assertErrorsAlmostEqual(results_1, expected_results_1) self.assertErrorsAlmostEqual(results_2, expected_results_2)
def test_approx_random_mixed_unitary_channel_1q(self): noise1 = UnitaryGate(random_unitary(2, seed=123)) noise2 = UnitaryGate(random_unitary(2, seed=456)) noise = QuantumError([(noise1, 0.7), (noise2, 0.3)]) for opstr in ['pauli', 'reset']: new_result = approximate_quantum_error(noise, operator_string=opstr) old_result = self.old_approximate_quantum_error( noise, operator_string=opstr) self.assertEqual(new_result, old_result) for opstr in ['clifford']: # cannot compare due to error in old implementation with self.assertRaises(NoiseError): self.old_approximate_quantum_error(noise, operator_string=opstr)
def test_approx_random_mixed_unitary_channel_2q(self): noise1 = UnitaryGate(random_unitary(4, seed=123)) noise2 = UnitaryGate(random_unitary(4, seed=456)) noise = QuantumError([(noise1, 0.7), (noise2, 0.3)]) for opstr in ['pauli']: new_result = approximate_quantum_error(noise, operator_string=opstr) old_result = self.old_approximate_quantum_error( noise, operator_string=opstr) self.assertEqual(new_result, old_result) for opstr in ['reset']: new_result = approximate_quantum_error(noise, operator_string=opstr) old_result = self.old_approximate_quantum_error( noise, operator_string=opstr) self.assertGreaterEqual(process_fidelity(noise, new_result), process_fidelity(noise, old_result))
def test_pauli_conversion_unitary(self): """Test conversion of Pauli channel kraus to unitary qobj""" a_i = np.sqrt(0.25) * standard_gate_unitary('id') a_x = np.sqrt(0.25) * standard_gate_unitary('x') a_y = np.sqrt(0.25) * standard_gate_unitary('y') a_z = np.sqrt(0.25) * standard_gate_unitary('z') error_dict = QuantumError([a_i, a_x, a_y, a_z], standard_gates=False).to_dict() self.assertEqual(error_dict['type'], 'qerror') self.assertAlmostEqual( np.linalg.norm( np.array(4 * [0.25]) - np.array(error_dict['probabilities'])), 0.0) for instr in error_dict['instructions']: self.assertEqual(len(instr), 1) self.assertIn(instr[0]['name'], ['unitary', 'id']) self.assertEqual(instr[0]['qubits'], [0])
def test_to_quantumchannel_circuit(self): """Test to_quantumchannel for circuit inputs.""" noise_ops = [([{ 'name': 'reset', 'qubits': [0] }], 0.2), ([{ 'name': 'reset', 'qubits': [1] }], 0.3), ([{ 'name': 'id', 'qubits': [0] }], 0.5)] error = QuantumError(noise_ops) reset = SuperOp( np.array([[1, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])) iden = SuperOp(np.eye(4)) target = 0.2 * iden.tensor(reset) + 0.3 * reset.tensor( iden) + 0.5 * iden.tensor(iden) self.assertEqual(target, error.to_quantumchannel())
def test_raise_non_multiqubit_kraus(self): """Test exception is raised for non-multiqubit input.""" A0 = np.sqrt(0.5) * np.diag([1, 1, 1]) A1 = np.sqrt(0.5) * np.diag([1, 1, -1]) self.assertRaises(NoiseError, lambda: QuantumError([A0, A1]))
def test_raise_non_cptp_kraus(self): """Test exception is raised for non-CPTP input.""" A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]]) A1 = np.array([[0, 0], [np.sqrt(0.3), 0]]) self.assertRaises(NoiseError, lambda: QuantumError([A0, A1])) self.assertRaises(NoiseError, lambda: QuantumError([A0]))
def test_raise_probabilities_normalized_unitary_kraus(self): """Test exception is raised for unitary kraus probs greater than 1.""" A0 = np.sqrt(0.9) * np.eye(2) A1 = np.sqrt(0.2) * np.diag([1, -1]) self.assertRaises(NoiseError, lambda: QuantumError([A0, A1]))
def test_raise_non_cptp_kraus(self): """Test exception is raised for non-CPTP input.""" a_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex) a_1 = np.array([[0, 0], [np.sqrt(0.3), 0]], dtype=complex) self.assertRaises(NoiseError, lambda: QuantumError([a_0, a_1])) self.assertRaises(NoiseError, lambda: QuantumError([a_0]))