def test_single_qubit_matrix_to_gates_tolerance_z(): z = np.diag([1, np.exp(1j * 0.01)]) optimized_away = cirq.single_qubit_matrix_to_gates(z, tolerance=0.1) assert len(optimized_away) == 0 kept = cirq.single_qubit_matrix_to_gates(z, tolerance=0.0001) assert len(kept) == 1
def test_single_qubit_matrix_to_gates_tolerance_z(): z = np.diag([1, np.exp(1j * 0.01)]) optimized_away = cirq.single_qubit_matrix_to_gates( z, tolerance=0.1) assert len(optimized_away) == 0 kept = cirq.single_qubit_matrix_to_gates(z, tolerance=0.0001) assert len(kept) == 1
def test_single_qubit_matrix_to_gates_tolerance_xy(): c, s = np.cos(0.01), np.sin(0.01) xy = np.array([[c, -s], [s, c]]) optimized_away = cirq.single_qubit_matrix_to_gates(xy, tolerance=0.1) assert len(optimized_away) == 0 kept = cirq.single_qubit_matrix_to_gates(xy, tolerance=0.0001) assert len(kept) == 1
def test_single_qubit_matrix_to_gates_tolerance_xy(): c, s = np.cos(0.01), np.sin(0.01) xy = np.array([[c, -s], [s, c]]) optimized_away = cirq.single_qubit_matrix_to_gates( xy, tolerance=0.1) assert len(optimized_away) == 0 kept = cirq.single_qubit_matrix_to_gates(xy, tolerance=0.0001) assert len(kept) == 1
def test_single_qubit_matrix_to_gates_tolerance_half_turn_phasing(): a = np.pi / 2 + 0.01 c, s = np.cos(a), np.sin(a) nearly_x = np.array([[c, -s], [s, c]]) z1 = np.diag([1, np.exp(1j * 1.2)]) z2 = np.diag([1, np.exp(1j * 1.6)]) phased_nearly_x = z1.dot(nearly_x).dot(z2) optimized_away = cirq.single_qubit_matrix_to_gates(phased_nearly_x, tolerance=0.1) assert len(optimized_away) == 2 kept = cirq.single_qubit_matrix_to_gates(phased_nearly_x, tolerance=0.0001) assert len(kept) == 3
def test_single_qubit_matrix_to_gates_tolerance_half_turn_phasing(): a = np.pi / 2 + 0.01 c, s = np.cos(a), np.sin(a) nearly_x = np.array([[c, -s], [s, c]]) z1 = np.diag([1, np.exp(1j * 1.2)]) z2 = np.diag([1, np.exp(1j * 1.6)]) phased_nearly_x = z1.dot(nearly_x).dot(z2) optimized_away = cirq.single_qubit_matrix_to_gates( phased_nearly_x, tolerance=0.1) assert len(optimized_away) == 2 kept = cirq.single_qubit_matrix_to_gates( phased_nearly_x, tolerance=0.0001) assert len(kept) == 3
def test_single_qubit_matrix_to_gates_cases(intended_effect): for atol in [1e-1, 1e-8]: gates = cirq.single_qubit_matrix_to_gates(intended_effect, tolerance=atol / 10) assert len(gates) <= 3 assert sum(1 for g in gates if not isinstance(g, cirq.ZPowGate)) <= 1 assert_gates_implement_unitary(gates, intended_effect, atol=atol)
def test_unitary_decomp(): q = cirq.GridQubit(0, 0) random_unitary = random_single_qubit_unitary() circuit = cirq.Circuit( [term.on(q) for term in cirq.single_qubit_matrix_to_gates(random_unitary)] ) assert np.isclose(abs(np.trace(cirq.unitary(circuit).conj().T @ random_unitary)), 2.0)
def _decompose_two_qubit(self, operation: cirq.Operation) -> cirq.OP_TREE: """Decomposes a two qubit gate into XXPow, YYPow, and ZZPow plus single qubit gates.""" mat = cirq.unitary(operation) kak = cirq.kak_decomposition(mat, check_preconditions=False) for qubit, mat in zip(operation.qubits, kak.single_qubit_operations_before): gates = cirq.single_qubit_matrix_to_gates(mat, self.atol) for gate in gates: yield gate(qubit) two_qubit_gates = [cirq.XX, cirq.YY, cirq.ZZ] for two_qubit_gate, coefficient in zip(two_qubit_gates, kak.interaction_coefficients): yield (two_qubit_gate ** (-coefficient * 2 / np.pi))(*operation.qubits) for qubit, mat in zip(operation.qubits, kak.single_qubit_operations_after): for gate in cirq.single_qubit_matrix_to_gates(mat, self.atol): yield gate(qubit)
def test_single_qubit_matrix_to_gates_fuzz_half_turns_merge_z_gates( pre_turns, post_turns): intended_effect = cirq.dot(cirq.unitary(cirq.Z**(2 * pre_turns)), cirq.unitary(cirq.X), cirq.unitary(cirq.Z**(2 * post_turns))) gates = cirq.single_qubit_matrix_to_gates(intended_effect, tolerance=1e-7) assert len(gates) <= 2 assert_gates_implement_unitary(gates, intended_effect, atol=1e-6)
def test_single_qubit_matrix_to_gates_fuzz_half_turns_merge_z_gates( pre_turns, post_turns): intended_effect = cirq.dot( cirq.RotZGate(half_turns=2 * pre_turns).matrix(), cirq.X.matrix(), cirq.RotZGate(half_turns=2 * post_turns).matrix()) gates = cirq.single_qubit_matrix_to_gates(intended_effect, tolerance=0.0001) assert len(gates) <= 2 assert_gates_implement_unitary(gates, intended_effect)
def test_single_qubit_matrix_to_gates_fuzz_half_turns_merge_z_gates( pre_turns, post_turns): intended_effect = cirq.dot( cirq.RotZGate(half_turns=2 * pre_turns).matrix(), cirq.X.matrix(), cirq.RotZGate(half_turns=2 * post_turns).matrix()) gates = cirq.single_qubit_matrix_to_gates( intended_effect, tolerance=0.0001) assert len(gates) <= 2 assert_gates_implement_unitary(gates, intended_effect)
def matrix_to_sycamore_operations( target_qubits: List[cirq.GridQubit], matrix: np.ndarray) -> Tuple[cirq.OP_TREE, List[cirq.GridQubit]]: """A method to convert a unitary matrix to a list of Sycamore operations. This method will return a list of `cirq.Operation`s using the qubits and (optionally) ancilla qubits to implement the unitary matrix `matrix` on the target qubits `qubits`. The operations are also supported by `cirq.google.gate_sets.SYC_GATESET`. Args: target_qubits: list of qubits the returned operations will act on. The qubit order defined by the list is assumed to be used by the operations to implement `matrix`. matrix: a matrix that is guaranteed to be unitary and of size (2**len(qs), 2**len(qs)). Returns: A tuple of operations and ancilla qubits allocated. Operations: In case the matrix is supported, a list of operations `ops` is returned. `ops` acts on `qs` qubits and for which `cirq.unitary(ops)` is equal to `matrix` up to certain tolerance. In case the matrix is not supported, it might return NotImplemented to reduce the noise in the judge output. Ancilla qubits: In case ancilla qubits are allocated a list of ancilla qubits. Otherwise an empty list. . """ ops = NotImplemented if len(target_qubits) == 1: ops = cirq.single_qubit_matrix_to_gates(matrix) for i, x in enumerate(ops): ops[i] = cirq.GateOperation(x, [target_qubits[0]]) elif len(target_qubits) == 2: ops = cirq.two_qubit_matrix_to_operations(target_qubits[0], target_qubits[1], matrix, allow_partial_czs=False, atol=1e-4) elif len(target_qubits) == 3: ops = cirq.three_qubit_matrix_to_operations(target_qubits[0], target_qubits[1], target_qubits[2], matrix, atol=1e-4) return ops, []
def test_single_qubit_matrix_to_gates_known_y(): actual = cirq.single_qubit_matrix_to_gates(np.array([[0, -1j], [1j, 0]]), tolerance=0.01) assert cirq.approx_eq(actual, [cirq.Y], atol=1e-9)
def test_single_qubit_matrix_to_gates_known_y(): actual = cirq.single_qubit_matrix_to_gates( np.array([[0, -1j], [1j, 0]]), tolerance=0.01) assert actual == [cirq.Y]
def test_single_qubit_matrix_to_gates_known_z(): actual = cirq.single_qubit_matrix_to_gates( np.array([[1, 0], [0, -1]]), tolerance=0.01) assert actual == [cirq.Z]
def test_known_s_dag(): actual = cirq.single_qubit_matrix_to_gates( np.array([[1, 0], [0, -1j]]), tolerance=0.01) assert actual == [cirq.Z**-0.5]
def test_known_h(): actual = cirq.single_qubit_matrix_to_gates( np.array([[1, 1], [1, -1]]) * np.sqrt(0.5), tolerance=0.001) assert actual == [cirq.Y**-0.5, cirq.Z]
def _decompose_single_qubit_operation(self, op: cirq.Operation, _) -> cirq.OP_TREE: qubit = op.qubits[0] mat = cirq.unitary(op) for gate in cirq.single_qubit_matrix_to_gates(mat, self.atol): yield gate(qubit)
def _decompose_single_qubit(operation: cirq.Operation, atol: float) -> cirq.OP_TREE: qubit = operation.qubits[0] mat = cirq.unitary(operation) for gate in cirq.single_qubit_matrix_to_gates(mat, atol): yield gate(qubit)
def test_single_qubit_matrix_to_gates_cases(intended_effect): gates = cirq.single_qubit_matrix_to_gates(intended_effect, tolerance=0.0001) assert len(gates) <= 3 assert sum(1 for g in gates if not isinstance(g, cirq.RotZGate)) <= 1 assert_gates_implement_unitary(gates, intended_effect)
def test_single_qubit_matrix_to_gates_cases(intended_effect): gates = cirq.single_qubit_matrix_to_gates( intended_effect, tolerance=0.0001) assert len(gates) <= 3 assert sum(1 for g in gates if not isinstance(g, cirq.RotZGate)) <= 1 assert_gates_implement_unitary(gates, intended_effect)
def test_known_s_dag(): actual = cirq.single_qubit_matrix_to_gates(np.array([[1, 0], [0, -1j]]), tolerance=0.01) assert cirq.approx_eq(actual, [cirq.Z**-0.5], atol=1e-9)
def test_known_h(): actual = cirq.single_qubit_matrix_to_gates(np.array([[1, 1], [1, -1]]) * np.sqrt(0.5), tolerance=0.001) assert cirq.approx_eq(actual, [cirq.Y**-0.5, cirq.Z], atol=1e-9)