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_super_to_choi(): for noise_level in [0, 0.3, 1]: super_damping = kraus_to_super(amplitude_damping_kraus(noise_level, 1)) # Apply Pauli Y to get some complex numbers super_op = np.kron(channel(Y)[0], channel(Y)[0].conj()) @ super_damping choi_state = super_to_choi(super_op) # expected result q = LineQubit(0) choi_expected = _operation_to_choi( [AmplitudeDampingChannel(noise_level)(q), Y(q)]) assert np.allclose(choi_state, choi_expected)
def amplitude_damping_kraus(noise_level: float, num_qubits: int) -> List[np.ndarray]: """Returns the Kraus operators of an amplitude damping channel at a given noise level. If ``num_qubits > 1``, the Kraus operators corresponding to tensor product of many single-qubit amplitude damping channels are returned. """ noisy_op = AmplitudeDampingChannel(noise_level) local_kraus = list(channel(noisy_op)) return [ tensor_product(*tup) for tup in product(local_kraus, repeat=num_qubits) ]
def amplitude_damping_kraus( noise_level: float, num_qubits: int, ) -> List[np.ndarray]: """Returns the Kraus operators of the tensor product of local depolarizing channels acting on each qubit. """ local_noisy_op = AmplitudeDampingChannel(noise_level) local_kraus = list(channel(local_noisy_op)) return [ tensor_product(*kraus_string) for kraus_string in product(local_kraus, repeat=num_qubits) ]
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
def test_minimize_one_norm_with_amp_damp_choi(): for noise_level in [0.01, 0.02, 0.03]: q = LineQubit(0) ideal_matrix = _operation_to_choi(H(q)) basis_matrices = [ _operation_to_choi( [H(q), gate(q), AmplitudeDampingChannel(noise_level)(q)]) for gate in [I, Z] ] # Append reset channel reset_kraus = channel(ResetChannel()) basis_matrices.append(kraus_to_choi(reset_kraus)) optimal_coeffs = minimize_one_norm(ideal_matrix, basis_matrices) represented_mat = sum( [eta * mat for eta, mat in zip(optimal_coeffs, basis_matrices)]) assert np.allclose(ideal_matrix, represented_mat) # Optimal analytic result by Takagi (arXiv:2006.12509) expected = (1.0 + noise_level) / (1.0 - noise_level) assert np.isclose(np.linalg.norm(optimal_coeffs, 1), expected)