def test_push_z_gates_left(self):
        """Test that Z-basis after before controlled-Z-type gates on controls *and*
        targets get pushed behind."""
        def qfunc():
            qml.CZ(wires=[0, 2])
            qml.PauliZ(wires=2)
            qml.S(wires=0)

            qml.CNOT(wires=[0, 1])

            qml.CRZ(0.5, wires=[0, 1])
            qml.RZ(0.2, wires=2)
            qml.T(wires=0)
            qml.PauliZ(wires=0)

        transformed_qfunc = commute_controlled(direction="left")(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = [
            "PauliZ", "S", "RZ", "T", "PauliZ", "CZ", "CNOT", "CRZ"
        ]
        wires_expected = [
            Wires(2),
            Wires(0),
            Wires(2),
            Wires(0),
            Wires(0),
            Wires([0, 2])
        ] + [Wires([0, 1])] * 2

        compare_operation_lists(ops, names_expected, wires_expected)
    def test_commute_controlled_torch(self):
        """Test QNode and gradient in torch interface."""
        torch = pytest.importorskip("torch", minversion="1.8")

        original_qnode = qml.QNode(qfunc, dev, interface="torch")
        transformed_qnode = qml.QNode(transformed_qfunc,
                                      dev,
                                      interface="torch")

        original_input = torch.tensor([1.2, -0.35], requires_grad=True)
        transformed_input = torch.tensor([1.2, -0.35], requires_grad=True)

        original_result = original_qnode(original_input)
        transformed_result = transformed_qnode(transformed_input)

        # Check that the numerical output is the same
        assert qml.math.allclose(original_result, transformed_result)

        # Check that the gradient is the same
        original_result.backward()
        transformed_result.backward()

        assert qml.math.allclose(original_input.grad, transformed_input.grad)

        # Check operation list
        ops = transformed_qnode.qtape.operations
        compare_operation_lists(ops, expected_op_list, expected_wires_list)
    def test_commute_controlled_jax(self):
        """Test QNode and gradient in JAX interface."""
        jax = pytest.importorskip("jax")
        from jax import numpy as jnp

        from jax.config import config

        remember = config.read("jax_enable_x64")
        config.update("jax_enable_x64", True)

        original_qnode = qml.QNode(qfunc, dev, interface="jax")
        transformed_qnode = qml.QNode(transformed_qfunc, dev, interface="jax")

        input = jnp.array([0.3, 0.4], dtype=jnp.float64)

        # Check that the numerical output is the same
        assert qml.math.allclose(original_qnode(input),
                                 transformed_qnode(input))

        # Check that the gradient is the same
        assert qml.math.allclose(
            jax.grad(original_qnode)(input),
            jax.grad(transformed_qnode)(input))

        # Check operation list
        ops = transformed_qnode.qtape.operations
        compare_operation_lists(ops, expected_op_list, expected_wires_list)
    def test_commute_controlled_tf(self):
        """Test QNode and gradient in tensorflow interface."""
        tf = pytest.importorskip("tensorflow")

        original_qnode = qml.QNode(qfunc, dev, interface="tf")
        transformed_qnode = qml.QNode(transformed_qfunc, dev, interface="tf")

        original_input = tf.Variable([0.8, -0.6])
        transformed_input = tf.Variable([0.8, -0.6])

        original_result = original_qnode(original_input)
        transformed_result = transformed_qnode(transformed_input)

        # Check that the numerical output is the same
        assert qml.math.allclose(original_result, transformed_result)

        # Check that the gradient is the same
        with tf.GradientTape() as tape:
            loss = original_qnode(original_input)
        original_grad = tape.gradient(loss, original_input)

        with tf.GradientTape() as tape:
            loss = transformed_qnode(transformed_input)
        transformed_grad = tape.gradient(loss, transformed_input)

        assert qml.math.allclose(original_grad, transformed_grad)

        # Check operation list
        ops = transformed_qnode.qtape.operations
        compare_operation_lists(ops, expected_op_list, expected_wires_list)
    def test_push_z_gates_right(self):
        """Test that Z-basis gates before controlled-Z-type gates on controls *and* targets get pushed ahead."""
        def qfunc():
            qml.PauliZ(wires=2)
            qml.S(wires=0)
            qml.CZ(wires=[0, 2])

            qml.CNOT(wires=[0, 1])

            qml.PhaseShift(0.2, wires=2)
            qml.T(wires=0)
            qml.PauliZ(wires=0)
            qml.CRZ(0.5, wires=[0, 1])

        transformed_qfunc = commute_controlled()(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = [
            "CZ", "PauliZ", "CNOT", "PhaseShift", "CRZ", "S", "T", "PauliZ"
        ]
        wires_expected = (
            [Wires([0, 2]), Wires(2),
             Wires([0, 1]), Wires(2)] + [Wires([0, 1])] + [Wires(0)] * 3)

        compare_operation_lists(ops, names_expected, wires_expected)
    def test_push_x_gates_right(self):
        """Test that X-basis gates before controlled-X-type gates on targets get pushed ahead."""
        def qfunc():
            qml.PauliX(wires=2)
            qml.CNOT(wires=[0, 2])
            qml.RX(0.2, wires=2)
            qml.Toffoli(wires=[0, 1, 2])
            qml.SX(wires=1)
            qml.PauliX(wires=1)
            qml.CRX(0.1, wires=[0, 1])

        transformed_qfunc = commute_controlled()(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = [
            "CNOT", "Toffoli", "PauliX", "RX", "CRX", "SX", "PauliX"
        ]
        wires_expected = [
            Wires([0, 2]),
            Wires([0, 1, 2]),
            Wires(2),
            Wires(2),
            Wires([0, 1]),
            Wires(1),
            Wires(1),
        ]
        compare_operation_lists(ops, names_expected, wires_expected)
示例#7
0
    def test_two_qubits_cnot_opposite_direction(self):
        """Test that two adjacent CNOTs with the control/target flipped do NOT cancel."""
        def qfunc():
            qml.CNOT(wires=[0, 1])
            qml.CNOT(wires=[1, 0])

        transformed_qfunc = cancel_inverses(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["CNOT"] * 2
        wires_expected = [Wires([0, 1]), Wires([1, 0])]
        compare_operation_lists(ops, names_expected, wires_expected)
示例#8
0
    def test_two_qubits_no_inverse(self):
        """Test that a two-qubit circuit self-inverse on each qubit does not cancel."""
        def qfunc():
            qml.Hadamard(wires=0)
            qml.Hadamard(wires=1)

        transformed_qfunc = cancel_inverses(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["Hadamard"] * 2
        wires_expected = [Wires(0), Wires(1)]
        compare_operation_lists(ops, names_expected, wires_expected)
    def test_gate_blocked_different_basis(self, direction):
        """Test that gates do not get pushed through controlled gates whose target bases don't match."""
        def qfunc():
            qml.PauliZ(wires="b")
            qml.CNOT(wires=[2, "b"])
            qml.PauliY(wires="b")

        transformed_qfunc = commute_controlled(direction=direction)(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["PauliZ", "CNOT", "PauliY"]
        wires_expected = [Wires("b"), Wires([2, "b"]), Wires("b")]
        compare_operation_lists(ops, names_expected, wires_expected)
示例#10
0
    def test_one_qubit_no_inverse(self):
        """Test that a one-qubit circuit with a gate in the way does not cancel the inverses."""
        def qfunc():
            qml.Hadamard(wires=0)
            qml.RZ(0.3, wires=0)
            qml.Hadamard(wires=0)

        transformed_qfunc = cancel_inverses(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["Hadamard", "RZ", "Hadamard"]
        wires_expected = [Wires(0)] * 3
        compare_operation_lists(ops, names_expected, wires_expected)
示例#11
0
    def test_controlled_rotation_no_merge(self):
        """Test that adjacent controlled rotations on the same wires in different order don't merge."""
        def qfunc():
            qml.CRX(0.2, wires=["w1", "w2"])
            qml.CRX(0.3, wires=["w2", "w1"])

        transformed_qfunc = merge_rotations()(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["CRX", "CRX"]
        wires_expected = [Wires(["w1", "w2"]), Wires(["w2", "w1"])]
        compare_operation_lists(ops, names_expected, wires_expected)

        assert ops[0].parameters[0] == 0.2
        assert ops[1].parameters[0] == 0.3
示例#12
0
    def test_three_qubits_inverse_after_cnot(self):
        """Test that a three-qubit circuit with a CNOT still allows cancellation."""
        def qfunc():
            qml.Hadamard(wires=0)
            qml.PauliX(wires=1)
            qml.CNOT(wires=[0, 2])
            qml.RZ(0.5, wires=2)
            qml.PauliX(wires=1)

        transformed_qfunc = cancel_inverses(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["Hadamard", "CNOT", "RZ"]
        wires_expected = [Wires(0), Wires([0, 2]), Wires(2)]
        compare_operation_lists(ops, names_expected, wires_expected)
    def test_gate_with_no_basis(self, direction):
        """Test that gates with no basis specified are ignored."""
        def qfunc():
            qml.PauliX(wires=2)
            qml.ControlledQubitUnitary(np.array([[0, 1], [1, 0]]),
                                       control_wires=0,
                                       wires=2)
            qml.PauliX(wires=2)

        transformed_qfunc = commute_controlled(direction=direction)(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["PauliX", "ControlledQubitUnitary", "PauliX"]
        wires_expected = [Wires(2), Wires([0, 2]), Wires(2)]
        compare_operation_lists(ops, names_expected, wires_expected)
示例#14
0
    def test_one_qubit_rotation_blocked(self):
        """Test that rotations on one-qubit separated by a "blocking" operation don't merge."""
        def qfunc():
            qml.RX(0.5, wires=0)
            qml.Hadamard(wires=0)
            qml.RX(0.4, wires=0)

        transformed_qfunc = merge_rotations()(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["RX", "Hadamard", "RX"]
        wires_expected = [Wires(0)] * 3
        compare_operation_lists(ops, names_expected, wires_expected)

        assert ops[0].parameters[0] == 0.5
        assert ops[2].parameters[0] == 0.4
示例#15
0
    def test_two_qubits_rotation_blocked(self):
        """Test that rotations on a two-qubit system separated by a "blocking" operation
        don't merge."""
        def qfunc():
            qml.RX(-0.42, wires=0)
            qml.CNOT(wires=[0, 1])
            qml.RX(0.8, wires=0)

        transformed_qfunc = merge_rotations()(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["RX", "CNOT", "RX"]
        wires_expected = [Wires(0), Wires([0, 1]), Wires(0)]
        compare_operation_lists(ops, names_expected, wires_expected)

        assert ops[0].parameters[0] == -0.42
        assert ops[2].parameters[0] == 0.8
示例#16
0
    def test_undo_swaps_autograd(self):
        """Test QNode and gradient in autograd interface."""

        original_qnode = qml.QNode(qfunc, dev)
        transformed_qnode = qml.QNode(transformed_qfunc, dev)

        input = np.array([0.1, 0.2], requires_grad=True)

        # Check that the numerical output is the same
        assert qml.math.allclose(original_qnode(input), transformed_qnode(input))

        # Check that the gradient is the same
        assert qml.math.allclose(
            qml.grad(original_qnode)(input), qml.grad(transformed_qnode)(input)
        )

        # Check operation list
        ops = transformed_qnode.qtape.operations
        compare_operation_lists(ops, expected_op_list, expected_wires_list)
    def test_dont_push_x_gates(self, direction):
        """Test that X-basis gates before controlled-X-type gates on controls don't get pushed."""
        def qfunc():
            qml.PauliX(wires="a")
            qml.CNOT(wires=["a", "c"])
            qml.RX(0.2, wires="a")
            qml.Toffoli(wires=["c", "a", "b"])

        transformed_qfunc = commute_controlled(direction=direction)(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["PauliX", "CNOT", "RX", "Toffoli"]
        wires_expected = [
            Wires("a"),
            Wires(["a", "c"]),
            Wires("a"),
            Wires(["c", "a", "b"])
        ]
        compare_operation_lists(ops, names_expected, wires_expected)
示例#18
0
    def test_three_qubits_toffolis(self):
        """Test that Toffolis on different permutations of wires cancel correctly."""
        def qfunc():
            # These two will cancel
            qml.Toffoli(wires=["a", "b", "c"])
            qml.Toffoli(wires=["b", "a", "c"])
            # These three will not cancel
            qml.Toffoli(wires=["a", "b", "c"])
            qml.Toffoli(wires=["a", "c", "b"])
            qml.Toffoli(wires=["a", "c", "d"])

        transformed_qfunc = cancel_inverses(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["Toffoli"] * 3
        wires_expected = [
            Wires(["a", "b", "c"]),
            Wires(["a", "c", "b"]),
            Wires(["a", "c", "d"])
        ]
        compare_operation_lists(ops, names_expected, wires_expected)
示例#19
0
    def test_two_qubits_merge_gate_subset(self):
        """Test that specifying a subset of operations to include merges correctly."""
        def qfunc():
            qml.CRX(0.1, wires=[0, 1])
            qml.CRX(0.2, wires=[0, 1])
            qml.RY(0.3, wires=["a"])
            qml.RY(0.5, wires=["a"])
            qml.RX(-0.5, wires=[2])
            qml.RX(0.2, wires=[2])

        transformed_qfunc = merge_rotations(include_gates=["RX", "CRX"])(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["CRX", "RY", "RY", "RX"]
        wires_expected = [Wires([0, 1]), Wires("a"), Wires("a"), Wires(2)]
        compare_operation_lists(ops, names_expected, wires_expected)

        assert qml.math.isclose(ops[0].parameters[0], 0.3)
        assert qml.math.isclose(ops[1].parameters[0], 0.3)
        assert qml.math.isclose(ops[2].parameters[0], 0.5)
        assert qml.math.isclose(ops[3].parameters[0], -0.3)
    def test_dont_push_y_gates(self, direction):
        """Test that Y-basis gates next to controlled-Y-type gates on controls don't get pushed."""
        def qfunc():
            qml.CRY(-0.2, wires=["a", 2])
            qml.PauliY(wires="a")
            qml.CNOT(wires=[1, 2])
            qml.CY(wires=["a", 1])
            qml.RY(0.3, wires="a")

        transformed_qfunc = commute_controlled()(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["CRY", "PauliY", "CNOT", "CY", "RY"]
        wires_expected = [
            Wires(["a", 2]),
            Wires("a"),
            Wires([1, 2]),
            Wires(["a", 1]),
            Wires("a")
        ]
        compare_operation_lists(ops, names_expected, wires_expected)
    def test_push_y_gates_left(self):
        """Test that Y-basis gates after controlled-Y-type gates on targets get pushed behind."""
        def qfunc():
            qml.CRY(-0.5, wires=["a", 2])
            qml.PauliY(wires=2)
            qml.CNOT(wires=[1, 2])
            qml.CY(wires=["a", 1])
            qml.RY(0.3, wires=1)

        transformed_qfunc = commute_controlled(direction="left")(qfunc)

        ops = qml.transforms.make_tape(transformed_qfunc)().operations

        names_expected = ["PauliY", "CRY", "CNOT", "RY", "CY"]
        wires_expected = [
            Wires(2),
            Wires(["a", 2]),
            Wires([1, 2]),
            Wires(1),
            Wires(["a", 1])
        ]
        compare_operation_lists(ops, names_expected, wires_expected)