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_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_seqs, signs, norm = sample_sequence(ideal_circ, [representation], random_state=rng) noisy_sequence = imp_seqs[0].with_noise(cirq.depolarize(BASE_NOISE)) sequence_choi = _circuit_to_choi(noisy_sequence) choi_unbiased_estimates.append(norm * signs[0] * 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_amplitude_damping_representation_with_choi( gate: Gate, noise: float, circuit_type: str, ): """Tests the representation by comparing exact Choi matrices.""" q = LineQubit(0) ideal_circuit = convert_from_mitiq(Circuit(gate.on(q)), circuit_type) ideal_choi = _circuit_to_choi(Circuit(gate.on(q))) op_rep = _represent_operation_with_amplitude_damping_noise( ideal_circuit, noise, ) choi_components = [] for noisy_op, coeff in op_rep.basis_expansion.items(): implementable_circ = noisy_op.circuit() depolarizing_op = AmplitudeDampingChannel(noise).on(q) # Apply noise after each sequence. # NOTE: noise is not applied after each operation. implementable_circ.append(depolarizing_op) sequence_choi = _operation_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**-8)
def test_biased_noise_representation_with_choi( gate: Gate, epsilon: float, eta: 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_local_biased_noise( Circuit(gate.on(*qreg)), epsilon, eta ) choi_components = [] # Define biased noise channel a = 1 - epsilon b = epsilon * (3 * eta + 1) / (3 * (eta + 1)) c = epsilon / (3 * (eta + 1)) mix = [ (a, unitary(I)), (b, unitary(Z)), (c, unitary(X)), (c, unitary(Y)), ] for noisy_op, coeff in op_rep.basis_expansion.items(): implementable_circ = noisy_op.circuit() # Apply noise after each sequence. # NOTE: noise is not applied after each operation. biased_op = ops.MixedUnitaryChannel(mix).on_each(*qreg) implementable_circ.append(biased_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 = represent_operations_in_circuit_with_local_depolarizing_noise( ideal_circuit=ideal_circ, noise_level=BASE_NOISE, ) choi_unbiased_estimates = [] rng = np.random.RandomState(1) for _ in range(500): imp_circs, signs, norm = sample_circuit(ideal_circ, rep_list, random_state=rng) noisy_imp_circ = imp_circs[0].with_noise(cirq.depolarize(BASE_NOISE)) sequence_choi = _circuit_to_choi(noisy_imp_circ) choi_unbiased_estimates.append(norm * signs[0] * 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_find_optimal_representation_depolarizing_two_qubit_gates(circ_type): """Test optimal representation agrees with a known analytic result.""" for ideal_gate, noise_level in product([CNOT, CZ], [0.1, 0.5]): q = LineQubit.range(2) ideal_op = Circuit(ideal_gate(*q)) implementable_circuits = [Circuit(ideal_op)] # Append two-qubit-gate with Paulis on one qubit for gate in [X, Y, Z]: implementable_circuits.append(Circuit([ideal_op, gate(q[0])])) implementable_circuits.append(Circuit([ideal_op, gate(q[1])])) # Append two-qubit gate with Paulis on both qubits for gate_a, gate_b in product([X, Y, Z], repeat=2): implementable_circuits.append( Circuit([ideal_op, gate_a(q[0]), gate_b(q[1])]) ) noisy_circuits = [ circ + Circuit(DepolarizingChannel(noise_level).on_each(*q)) for circ in implementable_circuits ] super_operators = [ choi_to_super(_circuit_to_choi(circ)) for circ in noisy_circuits ] # Define circuits with native types implementable_native = [ convert_from_mitiq(c, circ_type) for c in implementable_circuits ] ideal_op_native = convert_from_mitiq(ideal_op, circ_type) noisy_operations = [ NoisyOperation(ideal, real) for ideal, real in zip(implementable_native, super_operators) ] # Find optimal representation noisy_basis = NoisyBasis(*noisy_operations) rep = find_optimal_representation( ideal_op_native, noisy_basis, tol=1.0e-8 ) # Expected analytical result expected_rep = represent_operation_with_local_depolarizing_noise( ideal_op_native, noise_level, ) assert np.allclose(np.sort(rep.coeffs), np.sort(expected_rep.coeffs)) assert rep == expected_rep
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.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_find_optimal_representation_single_qubit_amp_damping(circ_type): """Test optimal representation of agrees with a known analytic result.""" for ideal_gate, noise_level in product([X, Y, H], [0.1, 0.3]): q = LineQubit(0) ideal_op = Circuit(ideal_gate(q)) implementable_circuits = [Circuit(ideal_op)] # Add ideal gate followed by Paulis and reset for gate in [Z, reset]: implementable_circuits.append(Circuit([ideal_op, gate(q)])) noisy_circuits = [ circ + Circuit(AmplitudeDampingChannel(noise_level).on_each(q)) for circ in implementable_circuits ] super_operators = [ choi_to_super(_circuit_to_choi(circ)) for circ in noisy_circuits ] # Define circuits with native types implementable_native = [ convert_from_mitiq(c, circ_type) for c in implementable_circuits ] ideal_op_native = convert_from_mitiq(ideal_op, circ_type) noisy_operations = [ NoisyOperation(ideal, real) for ideal, real in zip(implementable_native, super_operators) ] # Find optimal representation noisy_basis = NoisyBasis(*noisy_operations) rep = find_optimal_representation( ideal_op_native, noisy_basis, tol=1.0e-7, initial_guess=[0, 0, 0] ) # Expected analytical result expected_rep = _represent_operation_with_amplitude_damping_noise( ideal_op_native, noise_level, ) assert np.allclose(np.sort(rep.coeffs), np.sort(expected_rep.coeffs)) assert rep == expected_rep