def decompose_4x4_optimal(U): """Builds optimal decomposition of general 4x4 unitary matrix. This decomposition consists of at most 3 CNOT gates, 15 Rx/Ry gates and one R1 gate. Returns list of `Gate`s. """ assert is_unitary(U) magic_decomp = decompose_to_magic_diagonal(U) result = [] result += apply_on_qubit(su_to_gates(magic_decomp['VA']), 1) result += apply_on_qubit(su_to_gates(magic_decomp['VB']), 0) result += decompose_magic_N(magic_decomp['alpha']) result += apply_on_qubit(su_to_gates(magic_decomp['UA']), 1) result += apply_on_qubit(su_to_gates(magic_decomp['UB']), 0) # Adding global phase using Rz and R1. gl_phase = magic_decomp['global_phase'] + 0.25 * np.pi if np.abs(gl_phase) > 1e-9: result.append(GateSingle(Gate2('Rz', 2 * gl_phase), 0)) result.append(GateSingle(Gate2('R1', 2 * gl_phase), 0)) result = skip_identities(result) assert _allclose(U, gates_to_matrix(result, 2)) return result
def test_GateSingle_to_matrix(): assert np.allclose( GateSingle(Gate2('X'), 0, 2).to_matrix(), [[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) assert np.allclose( GateSingle(Gate2('X'), 1, 2).to_matrix(), [[0, 0, 1, 0], [0, 0, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0]])
def test_GateFC_to_matrix(): assert np.allclose( GateFC(Gate2('X'), 0).to_matrix(2), [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) assert np.allclose( GateFC(Gate2('X'), 1).to_matrix(2), [[1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0]])
def unitary2x2_to_gates(A): """Decomposes 2x2 unitary to gates Ry, Rz, R1. R1(x) = diag(1, exp(i*x)). """ assert is_unitary(A) phi = np.angle(np.linalg.det(A)) if np.abs(phi) < 1e-9: return su_to_gates(A) elif np.allclose(A, PAULI_X): return [Gate2('X')] else: A = np.diag([1.0, np.exp(-1j * phi)]) @ A return su_to_gates(A) + [Gate2('R1', phi)]
def su_to_gates(A): """Decomposes 2x2 special unitary to gates Ry, Rz. R_k(x) = exp(0.5*i*x*sigma_k). """ assert is_special_unitary(A) u00 = A[0, 0] u01 = A[0, 1] theta = np.arccos(np.abs(u00)) lmbda = np.angle(u00) mu = np.angle(u01) result = [] result.append(Gate2('Rz', lmbda - mu)) result.append(Gate2('Ry', 2 * theta)) result.append(Gate2('Rz', lmbda + mu)) return result
def decompose_magic_N(a): """Decomposes "Magic N" matrix into 3 CNOTs, 4 Rz and 1 Ry gate. Result is missing global phase pi/4. Implements cirquit on fig. 7 from [1]. """ t1 = 2 * a[2] - 0.5 * np.pi t2 = 0.5 * np.pi - 2 * a[0] t3 = 2 * a[1] - 0.5 * np.pi result = [] result.append(GateSingle(Gate2('Rz', 0.5 * np.pi), 1)) result.append(GateFC(Gate2('X'), 0)) result.append(GateSingle(Gate2('Rz', t1), 0)) result.append(GateSingle(Gate2('Ry', t2), 1)) result.append(GateFC(Gate2('X'), 1)) result.append(GateSingle(Gate2('Ry', t3), 1)) result.append(GateFC(Gate2('X'), 0)) result.append(GateSingle(Gate2('Rz', -0.5 * np.pi), 0)) N = magic_N(a) assert np.allclose(N, gates_to_matrix(result, 2) * np.exp(0.25j * np.pi)) return result
def dump_flips(): global flip_mask for qubit_id in range(qubit_count): if (flip_mask & (2**qubit_id)) != 0: result.append(GateSingle(Gate2('X'), qubit_id, qubit_count)) flip_mask = 0
def merge_gates(g1, g2): assert can_merge(g1, g2) new_gate2 = Gate2(g1.gate2.name, arg=g1.gate2.arg + g2.gate2.arg) return GateSingle(new_gate2, g1.qubit_id, g1.qubit_count)