def test_simplify_circuit_exponents(): qreg = LineQubit.range(2) circuit = Circuit([H.on(qreg[0]), CNOT.on(*qreg), Z.on(qreg[1])]) # Invert circuit inverse_circuit = cirq.inverse(circuit) inverse_repr = inverse_circuit.__repr__() inverse_qasm = inverse_circuit._to_qasm_output().__str__() # Expected circuit after simplification expected_inv = Circuit([Z.on(qreg[1]), CNOT.on(*qreg), H.on(qreg[0])]) expected_repr = expected_inv.__repr__() expected_qasm = expected_inv._to_qasm_output().__str__() # Check inverse_circuit is logically equivalent to expected_inverse # but they have a different representation assert inverse_circuit == expected_inv assert inverse_repr != expected_repr assert inverse_qasm != expected_qasm # Simplify the circuit _simplify_circuit_exponents(inverse_circuit) # Check inverse_circuit has the expected simplified representation simplified_repr = inverse_circuit.__repr__() simplified_qasm = inverse_circuit._to_qasm_output().__str__() assert inverse_circuit == expected_inv assert simplified_repr == expected_repr assert simplified_qasm == expected_qasm
def test_qubitop_to_paulisum_more_terms(self): # Given qubit_operator = ( QubitOperator("Z0 Z1 Z2", -1.5) + QubitOperator("X0", 2.5) + QubitOperator("Y1", 3.5) ) expected_qubits = (LineQubit(0), LineQubit(5), LineQubit(8)) expected_paulisum = ( PauliSum() + ( PauliString(Z.on(expected_qubits[0])) * PauliString(Z.on(expected_qubits[1])) * PauliString(Z.on(expected_qubits[2])) * -1.5 ) + (PauliString(X.on(expected_qubits[0]) * 2.5)) + (PauliString(Y.on(expected_qubits[1]) * 3.5)) ) # When paulisum = qubitop_to_paulisum(qubit_operator, qubits=expected_qubits) # Then self.assertEqual(paulisum.qubits, expected_qubits) self.assertEqual(paulisum, expected_paulisum)
def test_simple_pauli_deco_dict_CNOT(): """Tests that the _simple_pauli_deco_dict function returns a decomposition dicitonary which is consistent with a local depolarizing noise model. The channel acting on the state each qubit is assumed to be: D(rho) = = (1 - epsilon) rho + epsilon I/2 = (1 - p) rho + p/3 (X rho X + Y rho Y^dag + Z rho Z) """ # Deduce epsilon from BASE_NOISE epsilon = BASE_NOISE * 4.0 / 3.0 c_neg = -(1 / 4) * epsilon / (1 - epsilon) c_pos = 1 - 3 * c_neg qreg = LineQubit.range(2) # Get the decomposition of a CNOT gate deco = DECO_DICT[CNOT.on(*qreg)] # The first term of 'deco' corresponds to no error occurring first_coefficient, first_imp_seq = deco[0] assert np.isclose(c_pos * c_pos, first_coefficient) assert first_imp_seq == [CNOT.on(*qreg)] # The second term corresponds to a Pauli X error on one qubit second_coefficient, second_imp_seq = deco[1] assert np.isclose(c_pos * c_neg, second_coefficient) assert second_imp_seq == [CNOT.on(*qreg), X.on(qreg[0])] # The last term corresponds to two Pauli Z errors on both qubits last_coefficient, last_imp_seq = deco[-1] assert np.isclose(c_neg * c_neg, last_coefficient) assert last_imp_seq == [CNOT.on(*qreg), Z.on(qreg[0]), Z.on(qreg[1])]
def test_qubitop_to_paulisum_setting_qubits(self): # Given qubit_operator = QubitOperator("Z0 Z1", -1.5) expected_qubits = (LineQubit(0), LineQubit(5)) expected_paulisum = (PauliSum() + PauliString(Z.on(expected_qubits[0])) * PauliString(Z.on(expected_qubits[1])) * -1.5) # When paulisum = qubitop_to_paulisum(qubit_operator, qubits=expected_qubits) # Then self.assertEqual(paulisum.qubits, expected_qubits) self.assertEqual(paulisum, expected_paulisum)
def test_qubitop_to_paulisum_z0z1_operator(self): # Given qubit_operator = QubitOperator("Z0 Z1", -1.5) expected_qubits = (GridQubit(0, 0), GridQubit(1, 0)) expected_paulisum = (PauliSum() + PauliString(Z.on(expected_qubits[0])) * PauliString(Z.on(expected_qubits[1])) * -1.5) # When paulisum = qubitop_to_paulisum(qubit_operator) # Then self.assertEqual(paulisum.qubits, expected_qubits) self.assertEqual(paulisum, expected_paulisum)
def test_get_imp_sequences_no_simplify(gate: Gate): q = LineQubit(0) expected_imp_sequences = [ [gate.on(q)], [gate.on(q), X.on(q)], [gate.on(q), Y.on(q)], [gate.on(q), Z.on(q)], ] assert get_imp_sequences(gate.on(q), DECO_DICT) == expected_imp_sequences
def qubit_op_to_gate(operation: 'QubitOperator', qubit) -> 'SingleQubitPauliStringGateOperation': """Convert a qubit operation into a gate operations that can be digested by a Cirq simulator. Args: operation (QubitOperator) qubit (Qid) - a qubit on which the Pauli matrices will act. Returns: (gate) - a gate that can be executed on the qubit passed """ if operation == 'X': return X.on(qubit) if operation == 'Y': return Y.on(qubit) if operation == 'Z': return Z.on(qubit) raise ValueError('No gate identified in qubit_op_to_gate')
elif len(circuit.all_qubits()) == 2: obs = np.array([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) else: raise ValueError("The input must be a circuit with 1 or 2 qubits.") return noisy_simulation( circuit, BASE_NOISE, obs, ) # Simple identity 1-qubit circuit for testing q = LineQubit(1) oneq_circ = Circuit(Z.on(q), Z.on(q)) # Simple identity 2-qubit circuit for testing qreg = LineQubit.range(2) twoq_circ = Circuit( Y.on(qreg[1]), CNOT.on(*qreg), Y.on(qreg[1]), ) @mark.parametrize("circuit", [oneq_circ, twoq_circ]) @mark.parametrize("decomposition_dict", [NOISELESS_DECO_DICT, DECO_DICT_SIMP, DECO_DICT]) def test_execute_with_pec_one_qubit(circuit: Circuit, decomposition_dict: DecompositionDict):
def _simple_pauli_deco_dict(base_noise: float, simplify_paulis: bool = False ) -> DecompositionDict: """Returns a simple hard-coded decomposition dictionary to be used for testing and protoptyping. The decomposition is compatible with one-qubit or two-qubit circuits involving only Pauli and CNOT gates. The keys of the output dictionary are Pauli and CNOT operations. The decomposition assumes that Pauli and CNOT operations, followed by local depolarizing noise, are implementable. Args: base_noise: The depolarizing noise level. simplify_paulis: If True, products of Paulis are simplified to a single Pauli. If False, Pauli sequences are not simplified. Returns: decomposition_dict: The decomposition dictionary. """ # Initialize two qubits qreg = LineQubit.range(2) # Single-qubit Pauli operations i0 = I.on(qreg[0]) x0 = X.on(qreg[0]) y0 = Y.on(qreg[0]) z0 = Z.on(qreg[0]) i1 = I.on(qreg[1]) x1 = X.on(qreg[1]) y1 = Y.on(qreg[1]) z1 = Z.on(qreg[1]) single_paulis = [x0, y0, z0, x1, y1, z1] # Single-qubit decomposition coefficients epsilon = base_noise * 4 / 3 c_neg = -(1 / 4) * epsilon / (1 - epsilon) c_pos = 1 - 3 * c_neg assert np.isclose(c_pos + 3 * c_neg, 1.0) # Single-qubit decomposition dictionary decomposition_dict = {} if simplify_paulis: # Hard-coded simplified gates decomposition_dict = { x0: [(c_pos, [x0]), (c_neg, [i0]), (c_neg, [z0]), (c_neg, [y0])], y0: [(c_pos, [y0]), (c_neg, [z0]), (c_neg, [i0]), (c_neg, [x0])], z0: [(c_pos, [z0]), (c_neg, [y0]), (c_neg, [x0]), (c_neg, [i0])], x1: [(c_pos, [x1]), (c_neg, [i1]), (c_neg, [z1]), (c_neg, [y1])], y1: [(c_pos, [y1]), (c_neg, [z1]), (c_neg, [i1]), (c_neg, [x1])], z1: [(c_pos, [z1]), (c_neg, [y1]), (c_neg, [x1]), (c_neg, [i1])], } else: for local_paulis in [[x0, y0, z0], [x1, y1, z1]]: for key in local_paulis: key_deco_pos = [(c_pos, [key])] key_deco_neg = [(c_neg, [key, op]) for op in local_paulis] decomposition_dict[key] = ( key_deco_pos + key_deco_neg # type: ignore ) # Two-qubit Paulis xx = [x0, x1] xy = [x0, y1] xz = [x0, z1] yx = [y0, x1] yy = [y0, y1] yz = [y0, z1] zx = [z0, x1] zy = [z0, y1] zz = [z0, z1] double_paulis = [xx, xy, xz, yx, yy, yz, zx, zy, zz] # Two-qubit decomposition coefficients (assuming local noise) c_pos_pos = c_pos * c_pos c_pos_neg = c_neg * c_pos c_neg_neg = c_neg * c_neg assert np.isclose(c_pos_pos + 6 * c_pos_neg + 9 * c_neg_neg, 1.0) cnot = CNOT.on(qreg[0], qreg[1]) cnot_decomposition = [(c_pos_pos, [cnot])] for p in single_paulis: cnot_decomposition.append((c_pos_neg, [cnot] + [p])) for pp in double_paulis: cnot_decomposition.append((c_neg_neg, [cnot] + pp)) # type: ignore decomposition_dict[cnot] = cnot_decomposition # type: ignore return decomposition_dict # type: ignore
def test_get_imp_sequences_with_simplify(): q = LineQubit(0) expected_imp_sequences = [[X.on(q)], [I.on(q)], [Z.on(q)], [Y.on(q)]] assert get_imp_sequences(X.on(q), DECO_DICT_SIMP) == expected_imp_sequences