def test_sample_sequence_choi(gate: cirq.Gate): """Tests the sample_sequence by comparing the exact Choi matrices.""" qreg = cirq.LineQubit.range(gate.num_qubits()) ideal_op = gate.on(*qreg) ideal_circ = cirq.Circuit(ideal_op) noisy_op_tree = ([ideal_op] + [cirq.depolarize(BASE_NOISE)(q) for q in qreg]) ideal_choi = _operation_to_choi(ideal_op) noisy_choi = _operation_to_choi(noisy_op_tree) representation = represent_operation_with_local_depolarizing_noise( ideal_circ, BASE_NOISE, ) choi_unbiased_estimates = [] rng = np.random.RandomState(1) for _ in range(500): imp_seq, sign, norm = sample_sequence(ideal_circ, [representation], random_state=rng) noisy_sequence = imp_seq.with_noise(cirq.depolarize(BASE_NOISE)) sequence_choi = _circuit_to_choi(noisy_sequence) choi_unbiased_estimates.append(norm * sign * sequence_choi) choi_pec_estimate = np.average(choi_unbiased_estimates, axis=0) noise_error = np.linalg.norm(ideal_choi - noisy_choi) pec_error = np.linalg.norm(ideal_choi - choi_pec_estimate) assert pec_error < noise_error assert np.allclose(ideal_choi, choi_pec_estimate, atol=0.05)
def test_circuit_to_choi(): """Tests _circuit_to_choi is consistent with _operation_to_choi.""" base_noise = 0.01 q = LineQubit(0) noisy_operation = depolarize(base_noise).on(q) assert np.allclose( _operation_to_choi(noisy_operation), _circuit_to_choi(Circuit(noisy_operation)), ) noisy_sequence = [noisy_operation, noisy_operation] assert np.allclose( _operation_to_choi(noisy_sequence), _circuit_to_choi(Circuit(noisy_sequence)), )
def test_simple_pauli_deco_dict_with_Choi(gate: Gate): """Tests the decomposition by comparing the exact Choi matrices.""" qreg = LineQubit.range(gate.num_qubits()) ideal_choi = _operation_to_choi(gate.on(*qreg)) op_decomp = DECO_DICT[gate.on(*qreg)] choi_components = [] for coeff, imp_seq in op_decomp: # Apply noise after each sequence. # NOTE: noise is not applied after each operation. noisy_sequence = [imp_seq] + [depolarize(BASE_NOISE)(q) for q in qreg] sequence_choi = _operation_to_choi(noisy_sequence) choi_components.append(coeff * sequence_choi) combination_choi = np.sum(choi_components, axis=0) assert np.allclose(ideal_choi, combination_choi)
def test_sample_sequence_choi(gate: Gate): """Tests the sample_sequence by comparing the exact Choi matrices.""" qreg = LineQubit.range(gate.num_qubits()) ideal_op = gate.on(*qreg) noisy_op_tree = [ideal_op] + [depolarize(BASE_NOISE)(q) for q in qreg] ideal_choi = _operation_to_choi(gate.on(*qreg)) noisy_choi = _operation_to_choi(noisy_op_tree) choi_unbiased_estimates = [] for _ in range(500): imp_seq, sign, norm = sample_sequence(gate.on(*qreg), DECO_DICT) # Apply noise after each sequence. # NOTE: noise is not applied after each operation. noisy_sequence = [imp_seq] + [depolarize(BASE_NOISE)(q) for q in qreg] sequence_choi = _operation_to_choi(noisy_sequence) choi_unbiased_estimates.append(norm * sign * sequence_choi) choi_pec_estimate = np.average(choi_unbiased_estimates, axis=0) noise_error = np.linalg.norm(ideal_choi - noisy_choi) pec_error = np.linalg.norm(ideal_choi - choi_pec_estimate) assert pec_error < noise_error assert np.allclose(ideal_choi, choi_pec_estimate, atol=0.05)
def test_operation_to_choi(): """Tests the Choi matrix of a depolarizing channel is recovered.""" # Define first the expected result base_noise = 0.01 max_ent_state = np.array([1, 0, 0, 1]) / np.sqrt(2) identity_part = np.outer(max_ent_state, max_ent_state) mixed_part = np.eye(4) / 4.0 epsilon = base_noise * 4.0 / 3.0 choi = (1.0 - epsilon) * identity_part + epsilon * mixed_part # Choi matrix of the double application of a depolarizing channel choi_twice = sum([ ((1.0 - epsilon)**2 * identity_part), (2 * epsilon - epsilon**2) * mixed_part, ]) # Evaluate the Choi matrix of one or two depolarizing channels q = LineQubit(0) noisy_operation = depolarize(base_noise).on(q) noisy_sequence = [noisy_operation, noisy_operation] assert np.allclose(choi, _operation_to_choi(noisy_operation)) assert np.allclose(choi_twice, _operation_to_choi(noisy_sequence))
def test_depolarizing_representation_with_choi(gate: Gate, noise: float): """Tests the representation by comparing exact Choi matrices.""" qreg = LineQubit.range(gate.num_qubits()) ideal_choi = _operation_to_choi(gate.on(*qreg)) op_rep = represent_operation_with_global_depolarizing_noise( Circuit(gate.on(*qreg)), noise, ) choi_components = [] for noisy_op, coeff in op_rep.basis_expansion.items(): implementable_circ = noisy_op.ideal_circuit() # Apply noise after each sequence. # NOTE: noise is not applied after each operation. depolarizing_op = DepolarizingChannel(noise, len(qreg))(*qreg) implementable_circ.append(depolarizing_op) sequence_choi = _circuit_to_choi(implementable_circ) choi_components.append(coeff * sequence_choi) combination_choi = np.sum(choi_components, axis=0) assert np.allclose(ideal_choi, combination_choi, atol=10**-6)
def test_sample_circuit_choi(): """Tests the sample_circuit by comparing the exact Choi matrices.""" # A simple 2-qubit circuit qreg = cirq.LineQubit.range(2) ideal_circ = cirq.Circuit( cirq.X.on(qreg[0]), cirq.I.on(qreg[1]), cirq.CNOT.on(*qreg), ) noisy_circuit = ideal_circ.with_noise(cirq.depolarize(BASE_NOISE)) ideal_choi = _circuit_to_choi(ideal_circ) noisy_choi = _operation_to_choi(noisy_circuit) rep_list = [] for op in ideal_circ.all_operations(): rep_list.append( represent_operation_with_local_depolarizing_noise( cirq.Circuit(op), BASE_NOISE, )) choi_unbiased_estimates = [] rng = np.random.RandomState(1) for _ in range(500): imp_circ, sign, norm = sample_circuit(ideal_circ, rep_list, random_state=rng) noisy_imp_circ = imp_circ.with_noise(cirq.depolarize(BASE_NOISE)) sequence_choi = _circuit_to_choi(noisy_imp_circ) choi_unbiased_estimates.append(norm * sign * sequence_choi) choi_pec_estimate = np.average(choi_unbiased_estimates, axis=0) noise_error = np.linalg.norm(ideal_choi - noisy_choi) pec_error = np.linalg.norm(ideal_choi - choi_pec_estimate) assert pec_error < noise_error assert np.allclose(ideal_choi, choi_pec_estimate, atol=0.05)