def test_su2su2_to_tensor_products(self, U_pair): """Test SU(2) x SU(2) can be correctly factored into tensor products.""" true_matrix = qml.math.kron(np.array(U_pair[0]), np.array(U_pair[1])) A, B = _su2su2_to_tensor_products(true_matrix) assert check_matrix_equivalence(qml.math.kron(A, B), true_matrix)
def test_convert_to_su4(self, U): """Test a matrix in U(4) is correct converted to SU(4).""" U_su4 = _convert_to_su4(np.array(U)) # Ensure the determinant is correct and the mats are equivalent up to a phase assert qml.math.isclose(qml.math.linalg.det(U_su4), 1.0) assert check_matrix_equivalence(np.array(U), U_su4)
def test_zyz_decomposition_jax(self, U, expected_gate, expected_params): """Test that a one-qubit operation in JAX is correctly decomposed.""" jax = pytest.importorskip("jax") # Enable float64 support from jax.config import config remember = config.read("jax_enable_x64") config.update("jax_enable_x64", True) U = jax.numpy.array(U, dtype=jax.numpy.complex128) obtained_gates = zyz_decomposition(U, wire="a") assert len(obtained_gates) == 1 assert isinstance(obtained_gates[0], expected_gate) assert obtained_gates[0].wires == Wires("a") assert qml.math.allclose(qml.math.unwrap(obtained_gates[0].parameters), expected_params) if obtained_gates[0].num_params == 1: obtained_mat = qml.RZ(obtained_gates[0].parameters[0], wires=0).matrix else: obtained_mat = qml.Rot(*obtained_gates[0].parameters, wires=0).matrix assert check_matrix_equivalence(obtained_mat, U)
def test_zyz_decomposition_tf(self, U, expected_gate, expected_params): """Test that a one-qubit operation in Tensorflow is correctly decomposed.""" tf = pytest.importorskip("tensorflow") U = tf.Variable(U, dtype=tf.complex128) obtained_gates = zyz_decomposition(U, wire="a") assert len(obtained_gates) == 1 assert isinstance(obtained_gates[0], expected_gate) assert obtained_gates[0].wires == Wires("a") assert qml.math.allclose(qml.math.unwrap(obtained_gates[0].parameters), expected_params) print(qml.math.unwrap(obtained_gates[0].parameters)) print(expected_params) if obtained_gates[0].num_params == 1: # With TF and RZ, need to cast since can't just unwrap obtained_mat = qml.RZ(obtained_gates[0].parameters[0].numpy(), wires=0).matrix else: obtained_mat = qml.Rot(*qml.math.unwrap( obtained_gates[0].parameters), wires=0).matrix assert check_matrix_equivalence(obtained_mat, U)
def test_two_qubit_decomposition_tf(self, U, wires): """Test that a two-qubit operation in Tensorflow is correctly decomposed.""" tf = pytest.importorskip("tensorflow") U = tf.Variable(U, dtype=tf.complex128) obtained_decomposition = two_qubit_decomposition(U, wires=wires) with qml.tape.QuantumTape() as tape: for op in obtained_decomposition: qml.apply(op) obtained_matrix = get_unitary_matrix(tape, wire_order=wires)() assert check_matrix_equivalence(U, obtained_matrix, atol=1e-7)
def test_two_qubit_decomposition_1_cnot(self, U, wires): """Test that a two-qubit matrix using one CNOT is correctly decomposed.""" U = _convert_to_su4(np.array(U)) assert _compute_num_cnots(U) == 1 obtained_decomposition = two_qubit_decomposition(U, wires=wires) assert len(obtained_decomposition) == 5 with qml.tape.QuantumTape() as tape: for op in obtained_decomposition: qml.apply(op) obtained_matrix = get_unitary_matrix(tape, wire_order=wires)() assert check_matrix_equivalence(U, obtained_matrix, atol=1e-7)
def test_two_qubit_decomposition_tensor_products(self, U_pair, wires): """Test that a two-qubit tensor product matrix is correctly decomposed.""" U = _convert_to_su4( qml.math.kron(np.array(U_pair[0]), np.array(U_pair[1]))) assert _compute_num_cnots(U) == 0 obtained_decomposition = two_qubit_decomposition(U, wires=wires) assert len(obtained_decomposition) == 2 with qml.tape.QuantumTape() as tape: for op in obtained_decomposition: qml.apply(op) obtained_matrix = get_unitary_matrix(tape, wire_order=wires)() assert check_matrix_equivalence(U, obtained_matrix, atol=1e-7)
def test_zyz_decomposition(self, U, expected_gate, expected_params): """Test that a one-qubit matrix in isolation is correctly decomposed.""" obtained_gates = zyz_decomposition(U, Wires("a")) assert len(obtained_gates) == 1 assert isinstance(obtained_gates[0], expected_gate) assert obtained_gates[0].wires == Wires("a") assert qml.math.allclose(obtained_gates[0].parameters, expected_params) if obtained_gates[0].num_params == 1: obtained_mat = qml.RZ(obtained_gates[0].parameters[0], wires=0).matrix else: obtained_mat = qml.Rot(*obtained_gates[0].parameters, wires=0).matrix assert check_matrix_equivalence(obtained_mat, U)
def test_two_qubit_decomposition_tensor_products_torch( self, U_pair, wires): """Test that a two-qubit tensor product in Torch is correctly decomposed.""" torch = pytest.importorskip("torch") U1 = torch.tensor(U_pair[0], dtype=torch.complex128) U2 = torch.tensor(U_pair[1], dtype=torch.complex128) U = qml.math.kron(U1, U2) obtained_decomposition = two_qubit_decomposition(U, wires=wires) with qml.tape.QuantumTape() as tape: for op in obtained_decomposition: qml.apply(op) obtained_matrix = get_unitary_matrix(tape, wire_order=wires)() assert check_matrix_equivalence(U, obtained_matrix, atol=1e-7)
def test_two_qubit_decomposition_3_cnots(self, U, wires): """Test that a two-qubit matrix using 3 CNOTs is correctly decomposed.""" U = _convert_to_su4(np.array(U)) assert _compute_num_cnots(U) == 3 obtained_decomposition = two_qubit_decomposition(U, wires=wires) assert len(obtained_decomposition) == 10 with qml.tape.QuantumTape() as tape: for op in obtained_decomposition: qml.apply(op) obtained_matrix = get_unitary_matrix(tape, wire_order=wires)() # We check with a slightly great tolerance threshold here simply because the # test matrices were copied in here with reduced precision. assert check_matrix_equivalence(U, obtained_matrix, atol=1e-7)
def test_unitary_to_rot_multiple_two_qubit(num_reps): """Test that numerous two-qubit unitaries can be decomposed sequentially.""" dev = qml.device("default.qubit", wires=2) U = np.array(test_two_qubit_unitaries[1], dtype=np.complex128) def my_circuit(): for rep in range(num_reps): qml.QubitUnitary(U, wires=[0, 1]) return qml.expval(qml.PauliZ(0)) original_qnode = qml.QNode(my_circuit, dev) transformed_qnode = qml.QNode(unitary_to_rot(my_circuit), dev) original_matrix = qml.transforms.get_unitary_matrix(original_qnode)() transformed_matrix = qml.transforms.get_unitary_matrix(transformed_qnode)() assert check_matrix_equivalence(original_matrix, transformed_matrix, atol=1e-7)
def test_two_qubit_decomposition_jax(self, U, wires): """Test that a two-qubit operation in JAX is correctly decomposed.""" jax = pytest.importorskip("jax") from jax.config import config remember = config.read("jax_enable_x64") config.update("jax_enable_x64", True) U = jax.numpy.array(U, dtype=jax.numpy.complex128) obtained_decomposition = two_qubit_decomposition(U, wires=wires) with qml.tape.QuantumTape() as tape: for op in obtained_decomposition: qml.apply(op) obtained_matrix = get_unitary_matrix(tape, wire_order=wires)() assert check_matrix_equivalence(U, obtained_matrix, atol=1e-7)
def test_zyz_decomposition_torch(self, U, expected_gate, expected_params): """Test that a one-qubit operation in Torch is correctly decomposed.""" torch = pytest.importorskip("torch") U = torch.tensor(U, dtype=torch.complex128) obtained_gates = zyz_decomposition(U, wire="a") assert len(obtained_gates) == 1 assert isinstance(obtained_gates[0], expected_gate) assert obtained_gates[0].wires == Wires("a") assert qml.math.allclose(qml.math.unwrap(obtained_gates[0].parameters), expected_params) if obtained_gates[0].num_params == 1: obtained_mat = qml.RZ(obtained_gates[0].parameters[0], wires=0).matrix else: obtained_mat = qml.Rot(*obtained_gates[0].parameters, wires=0).matrix assert check_matrix_equivalence(obtained_mat, qml.math.unwrap(U))