def test_kak_vector_infidelity_ignore_equivalent_nontrivial(): x, y, z = np.pi / 4, 1, 0.5 kak_0 = cirq.kak_canonicalize_vector(x, y, z).interaction_coefficients kak_1 = cirq.kak_canonicalize_vector(x - 1e-3, y, z).interaction_coefficients inf_check_equivalent = kak_vector_infidelity(kak_0, kak_1, False) inf_ignore_equivalent = kak_vector_infidelity(kak_0, kak_1, True) assert inf_check_equivalent < inf_ignore_equivalent
def compile_two_qubit_gate(self, unitary: np.ndarray) -> TwoQubitGateCompilation: r"""Compute single qubit gates required to compile a desired unitary. Given a desired unitary U, this computes the sequence of 1-local gates $k_j$ such that the product $k_{n-1} A k_{n-2} A ... k_1 A k_0$ is close to U. Here A is the base_gate of the tabulation. Args: unitary: Unitary (U above) to compile. Returns: A TwoQubitGateCompilation object encoding the required local unitaries and resulting product above. """ unitary = np.asarray(unitary) kak_vec = cirq.kak_vector(unitary, check_preconditions=False) infidelities = kak_vector_infidelity(kak_vec, self.kak_vecs, ignore_equivalent_vectors=True) nearest_ind = infidelities.argmin() success = infidelities[nearest_ind] < self.max_expected_infidelity # shape (n,2,2,2) inner_gates = np.array(self.single_qubit_gates[nearest_ind]) if inner_gates.size == 0: # Only need base gate kR, kL, actual = _outer_locals_for_unitary(unitary, self.base_gate) return TwoQubitGateCompilation(self.base_gate, unitary, (kR, kL), actual, success) # reshape to operators on 2 qubits, (n,4,4) inner_gates = vector_kron(inner_gates[..., 0, :, :], inner_gates[..., 1, :, :]) assert inner_gates.ndim == 3 inner_product = reduce(lambda a, b: self.base_gate @ b @ a, inner_gates, self.base_gate) kR, kL, actual = _outer_locals_for_unitary(unitary, inner_product) out = [kR] out.extend(self.single_qubit_gates[nearest_ind]) out.append(kL) return TwoQubitGateCompilation(self.base_gate, unitary, tuple(out), actual, success)