def test_kron_factor_special_unitaries(f1, f2): p = linalg.kron(f1, f2) g, g1, g2 = linalg.kron_factor_4x4_to_2x2s(p) assert np.allclose(linalg.kron(g1, g2), p) assert abs(g - 1) < 0.000001 assert linalg.is_special_unitary(g1) assert linalg.is_special_unitary(g2)
def recompose_so4(a: np.ndarray, b: np.ndarray) -> np.ndarray: assert a.shape == (2, 2) assert b.shape == (2, 2) assert linalg.is_special_unitary(a) assert linalg.is_special_unitary(b) magic = np.array([[1, 0, 0, 1j], [0, 1j, 1, 0], [0, 1j, -1, 0], [1, 0, 0, -1j]]) * np.sqrt(0.5) result = np.real( combinators.dot(np.conj(magic.T), linalg.kron(a, b), magic)) assert linalg.is_orthogonal(result) return result
def test_kak_canonicalize_vector(x, y, z): i = np.eye(2) m = recompose_kak(1, (i, i), (x, y, z), (i, i)) g, (a1, a0), (x2, y2, z2), (b1, b0) = linalg.kak_canonicalize_vector(x, y, z) m2 = recompose_kak(g, (a1, a0), (x2, y2, z2), (b1, b0)) assert 0.0 <= x2 <= np.pi / 4 assert 0.0 <= y2 <= np.pi / 4 assert -np.pi / 4 <= z2 <= np.pi / 4 assert abs(x2) >= abs(y2) >= abs(z2) assert linalg.is_special_unitary(a1) assert linalg.is_special_unitary(a0) assert linalg.is_special_unitary(b1) assert linalg.is_special_unitary(b0) assert np.allclose(m, m2)
def _decompose_su(matrix: np.ndarray, controls: List['cirq.Qid'], target: 'cirq.Qid') -> List['cirq.Operation']: """Decomposes controlled special unitary gate into elementary gates. Result has O(len(controls)) operations. See [1], lemma 7.9. """ assert matrix.shape == (2, 2) assert is_special_unitary(matrix) assert len(controls) >= 1 a, b, c, _ = _decompose_abc(matrix) cnots = decompose_multi_controlled_x(controls[:-1], target, [controls[-1]]) return [ *_decompose_single_ctrl(c, controls[-1], target), *cnots, *_decompose_single_ctrl(b, controls[-1], target), *cnots, *_decompose_single_ctrl(a, controls[-1], target) ]
def decompose_multi_controlled_rotation( matrix: np.ndarray, controls: List['cirq.Qid'], target: 'cirq.Qid') -> List['cirq.Operation']: """Implements action of multi-controlled unitary gate. Returns a sequence of operations, which is equivalent to applying single-qubit gate with matrix `matrix` on `target`, controlled by `controls`. Result is guaranteed to consist exclusively of 1-qubit, CNOT and CCNOT gates. If matrix is special unitary, result has length `O(len(controls))`. Otherwise result has length `O(len(controls)**2)`. References: [1] Barenco, Bennett et al. Elementary gates for quantum computation. 1995. https://arxiv.org/pdf/quant-ph/9503016.pdf Args: matrix - 2x2 numpy unitary matrix (of real or complex dtype). controls - control qubits. targets - target qubits. Returns: A list of operations which, applied in a sequence, are equivalent to applying `MatrixGate(matrix).on(target).controlled_by(*controls)`. """ assert is_unitary(matrix) assert matrix.shape == (2, 2) if len(controls) == 0: return [ops.MatrixGate(matrix).on(target)] elif len(controls) == 1: return _decompose_single_ctrl(matrix, controls[0], target) elif is_special_unitary(matrix): return _decompose_su(matrix, controls, target) else: return _decompose_recursive(matrix, 1.0, controls, target, [])
def test_random_special_unitary(): u1 = random_special_unitary(2) u2 = random_special_unitary(2) assert is_special_unitary(u1) assert is_special_unitary(u2) assert not np.allclose(u1, u2)