def test_PauliRot_decomposition_XY(self):
        """Test that the decomposition for a XY rotation is correct."""

        theta = 0.4
        op = qml.PauliRot(theta, "XY", wires=[0, 1])
        decomp_ops = op.decomposition(theta, "XY", wires=[0, 1])

        assert len(decomp_ops) == 5

        assert decomp_ops[0].name == "Hadamard"
        assert decomp_ops[0].wires == [0]

        assert decomp_ops[1].name == "RX"
        assert decomp_ops[1].wires == [1]
        assert decomp_ops[1].params[0] == np.pi / 2

        assert decomp_ops[2].name == "MultiRZ"
        assert decomp_ops[2].wires == [0, 1]
        assert decomp_ops[2].params[0] == theta

        assert decomp_ops[3].name == "Hadamard"
        assert decomp_ops[3].wires == [0]

        assert decomp_ops[4].name == "RX"
        assert decomp_ops[4].wires == [1]
        assert decomp_ops[4].params[0] == -np.pi / 2
Example #2
0
    def expand(self):

        with qml.tape.QuantumTape() as tape:
            for i, pauli_word in enumerate(_state_preparation_pauli_words(len(self.wires))):
                qml.PauliRot(self.parameters[0][i], pauli_word, wires=self.wires)

        return tape
Example #3
0
def ArbitraryUnitary(weights, wires):
    """Implements an arbitrary unitary on the specified wires.

    An arbitrary unitary on :math:`n` wires is parametrized by :math:`4^n - 1`
    independent real parameters. This templates uses Pauli word rotations to
    parametrize the unitary.

    **Example**

    ArbitraryUnitary can be used as a building block, e.g. to parametrize arbitrary
    two-qubit operations in a circuit:

    .. code-block:: python

        @qml.template
        def arbitrary_nearest_neighbour_interaction(weights, wires):
            qml.broadcast(unitary=ArbitraryUnitary, pattern="double", wires=wires, params=weights)

    Args:
        weights (tensor_like): The angles of the Pauli word rotations, needs to have length :math:`4^n - 1`
            where :math:`n` is the number of wires the template acts upon.
        wires (Iterable or Wires): Wires that the template acts on. Accepts an iterable of numbers or strings, or
            a Wires object.
    """
    wires = Wires(wires)
    _preprocess(weights, wires)

    for i, pauli_word in enumerate(_all_pauli_words_but_identity(len(wires))):
        qml.PauliRot(weights[i], pauli_word, wires=wires)
Example #4
0
def ArbitraryUnitary(weights, wires):
    """Implements an arbitrary unitary on the specified wires.

    An arbitrary unitary on :math:`n` wires is parametrized by :math:`4^n - 1`
    independent real parameters. This templates uses Pauli word rotations to
    parametrize the unitary.

    **Example**

    ArbitraryUnitary can be used as a building block, e.g. to parametrize arbitrary
    two-qubit operations in a circuit:

    .. code-block:: python

        @qml.template
        def arbitrary_nearest_neighbour_interaction(weights, wires):
            qml.broadcast(unitary=ArbitraryUnitary, pattern="double", wires=wires, params=weights)

    Args:
        weights (array[float]): The angles of the Pauli word rotations, needs to have length :math:`4^n - 1`
            where :math:`n` is the number of wires the template acts upon.
        wires (List[int]): The wires on which the arbitrary unitary acts.
    """
    wires = check_wires(wires)

    n_wires = len(wires)
    expected_shape = (4 ** n_wires - 1,)
    check_shape(
        weights,
        expected_shape,
        msg="'weights' must be of shape {}; got {}." "".format(expected_shape, get_shape(weights)),
    )

    for i, pauli_word in enumerate(_all_pauli_words_but_identity(len(wires))):
        qml.PauliRot(weights[i], pauli_word, wires=wires)
Example #5
0
    def test_PauliRot_decomposition_XIYZ(self):
        """Test that the decomposition for a XIYZ rotation is correct."""

        theta = 0.4
        op = qml.PauliRot(theta, "XIYZ", wires=[0, 1, 2, 3])
        decomp_ops = op.decomposition(theta, "XIYZ", wires=[0, 1, 2, 3])

        assert len(decomp_ops) == 5

        assert decomp_ops[0].name == "Hadamard"
        assert decomp_ops[0].wires == Wires([0])

        assert decomp_ops[1].name == "RX"

        assert decomp_ops[1].wires == Wires([2])
        assert decomp_ops[1].data[0] == np.pi / 2

        assert decomp_ops[2].name == "MultiRZ"
        assert decomp_ops[2].wires == Wires([0, 2, 3])
        assert decomp_ops[2].data[0] == theta

        assert decomp_ops[3].name == "Hadamard"
        assert decomp_ops[3].wires == Wires([0])

        assert decomp_ops[4].name == "RX"

        assert decomp_ops[4].wires == Wires([2])
        assert decomp_ops[4].data[0] == -np.pi / 2
Example #6
0
    def test_multirz_generator(self, pauli_word):
        """Test that the generator of the MultiRZ gate is correct."""
        op = qml.PauliRot(0.3, pauli_word, wires=range(len(pauli_word)))
        gen = op.generator

        if pauli_word[0] == 'I':
            # this is the identity
            expected_gen = qml.Identity(wires=0) 
        else:
            expected_gen = getattr(
                qml, 'Pauli{}'.format(pauli_word[0]))(wires=0)

        for i, pauli in enumerate(pauli_word[1:]):
            i += 1
            if pauli == 'I':
                expected_gen = expected_gen @  qml.Identity(
                    wires=i) 
            else:
                expected_gen = expected_gen @ getattr(
                    qml, 'Pauli{}'.format(pauli))(wires=i)

        expected_gen_mat = expected_gen.matrix

        assert np.allclose(gen[0], expected_gen_mat)
        assert gen[1] == -0.5
def ArbitraryStatePreparation(weights, wires):
    """Implements an arbitrary state preparation on the specified wires.

    An arbitrary state on :math:`n` wires is parametrized by :math:`2^{n+1} - 2`
    independent real parameters. This templates uses Pauli word rotations to
    parametrize the unitary.

    **Example**

    ArbitraryStatePreparation can be used to train state preparations,
    for example using a circuit with some measurement observable ``H``:

    .. code-block:: python

        dev = qml.device("default.qubit", wires=4)

        @qml.qnode(dev)
        def vqe(weights):
            qml.ArbitraryStatePreparations(weights, wires=[0, 1, 2, 3])

            return qml.expval(qml.Hermitian(H, wires=[0, 1, 2, 3]))

    Args:
        weights (tensor_like): The angles of the Pauli word rotations, needs to have length :math:`2^(n+1) - 2`
            where :math:`n` is the number of wires the template acts upon.
        wires (Iterable or Wires): Wires that the template acts on. Accepts an iterable of numbers or strings, or
            a Wires object.
    """

    wires = Wires(wires)
    _preprocess(weights, wires)

    for i, pauli_word in enumerate(_state_preparation_pauli_words(len(wires))):
        qml.PauliRot(weights[i], pauli_word, wires=wires)
Example #8
0
def algebra_commutator(tape, observables, lie_algebra_basis_names, nqubits):
    """Calculate the Riemannian gradient in the Lie algebra with the parameter shift rule
    (see :meth:`LieAlgebraOptimizer.get_omegas`).

    Args:
        tape (.QuantumTape or .QNode): input circuit
        observables (list[.Observable]): list of observables to be measured. Can be grouped.
        lie_algebra_basis_names (list[str]): List of strings corresponding to valid Pauli words.
        nqubits (int): the number of qubits.

    Returns:
         func: Function which accepts the same arguments as the QNode. When called, this
         function will return the Lie algebra commutator.

    """
    tapes_plus_total = []
    tapes_min_total = []
    for obs in observables:
        for o in obs:
            # create a list of tapes for the plus and minus shifted circuits
            tapes_plus = [qml.tape.JacobianTape(p + "_p") for p in lie_algebra_basis_names]
            tapes_min = [qml.tape.JacobianTape(p + "_m") for p in lie_algebra_basis_names]

            # loop through all operations on the input tape
            for op in tape.operations:
                for t in tapes_plus + tapes_min:
                    with t:
                        qml.apply(op)
            for i, t in enumerate(tapes_plus):
                with t:
                    qml.PauliRot(
                        np.pi / 2,
                        lie_algebra_basis_names[i],
                        wires=list(range(nqubits)),
                    )
                    qml.expval(o)
            for i, t in enumerate(tapes_min):
                with t:
                    qml.PauliRot(
                        -np.pi / 2,
                        lie_algebra_basis_names[i],
                        wires=list(range(nqubits)),
                    )
                    qml.expval(o)
            tapes_plus_total.extend(tapes_plus)
            tapes_min_total.extend(tapes_min)
    return tapes_plus_total + tapes_min_total, None
Example #9
0
    def test_PauliRot_decomposition_Identity(self):
        """Test that decomposing the all-identity Pauli has no effect."""

        theta = 0.4
        op = qml.PauliRot(theta, "II", wires=[0, 1])
        decomp_ops = op.decomposition(theta, "II", wires=[0, 1])

        assert len(decomp_ops) == 0
Example #10
0
    def test_init_incorrect_pauli_word_length_error(self, pauli_word, wires):
        """Test that __init__ throws an error if a Pauli word of wrong length is supplied."""

        with pytest.raises(
            ValueError,
            match="The given Pauli word has length .*, length .* was expected for wires .*",
        ):
            qml.PauliRot(0.3, pauli_word, wires=wires)
Example #11
0
 def qfunc():
     qml.RZ(0.1, wires=0)
     qml.Hadamard(wires=0)
     # No rotation angles specified for PauliRot since it is a gate that
     # in principle acts on an arbitrary number of wires.
     qml.PauliRot(0.2, "X", wires=0)
     qml.RZ(0.1, wires=0)
     qml.Hadamard(wires=0)
Example #12
0
    def test_init_incorrect_pauli_word_error(self):
        """Test that __init__ throws an error if a wrong Pauli word is supplied."""

        with pytest.raises(
            ValueError,
            match='The given Pauli word ".*" contains characters that are not allowed.'
            " Allowed characters are I, X, Y and Z",
        ):
            qml.PauliRot(0.3, "IXYZV", wires=[0, 1, 2, 3, 4])
Example #13
0
    def test_PauliRot_all_Identity(self):
        """Test handling of the all-identity Pauli."""

        theta = 0.4
        op = qml.PauliRot(theta, "II", wires=[0, 1])
        decomp_ops = op.decomposition(theta, "II", wires=[0, 1])

        assert np.allclose(op.eigvals, np.exp(-1j * theta / 2) * np.ones(4))
        assert np.allclose(op.matrix / op.matrix[0, 0], np.eye(4))

        assert len(decomp_ops) == 0
    def test_PauliRot_decomposition_ZZ(self):
        """Test that the decomposition for a ZZ rotation is correct."""

        theta = 0.4
        op = qml.PauliRot(theta, "ZZ", wires=[0, 1])
        decomp_ops = op.decomposition(theta, "ZZ", wires=[0, 1])

        assert len(decomp_ops) == 1

        assert decomp_ops[0].name == "MultiRZ"
        assert decomp_ops[0].wires == [0, 1]
        assert decomp_ops[0].params[0] == theta
    def test_do_not_expand(self):
        """Test that a tape with single-parameter operations with
        unitary generators and non-parametric operations is not touched."""
        with qml.tape.JacobianTape() as tape:
            qml.RX(0.2, wires=0)
            qml.Hadamard(0)
            qml.PauliRot(0.9, "XY", wires=[0, 1])
            qml.SingleExcitationPlus(-1.2, wires=[1, 0])

        new_tape = qml.transforms.expand_nonunitary_gen(tape)

        assert tape.operations == new_tape.operations
Example #16
0
def op(op_name):
    ops_list = {
        "RX": qml.RX(0.123, wires=0),
        "RY": qml.RY(1.434, wires=0),
        "RZ": qml.RZ(2.774, wires=0),
        "S": qml.S(wires=0),
        "SX": qml.SX(wires=0),
        "T": qml.T(wires=0),
        "CNOT": qml.CNOT(wires=[0, 1]),
        "CZ": qml.CZ(wires=[0, 1]),
        "CY": qml.CY(wires=[0, 1]),
        "SWAP": qml.SWAP(wires=[0, 1]),
        "ISWAP": qml.ISWAP(wires=[0, 1]),
        "SISWAP": qml.SISWAP(wires=[0, 1]),
        "SQISW": qml.SQISW(wires=[0, 1]),
        "CSWAP": qml.CSWAP(wires=[0, 1, 2]),
        "PauliRot": qml.PauliRot(0.123, "Y", wires=0),
        "IsingXX": qml.IsingXX(0.123, wires=[0, 1]),
        "IsingXY": qml.IsingXY(0.123, wires=[0, 1]),
        "IsingYY": qml.IsingYY(0.123, wires=[0, 1]),
        "IsingZZ": qml.IsingZZ(0.123, wires=[0, 1]),
        "Identity": qml.Identity(wires=0),
        "Rot": qml.Rot(0.123, 0.456, 0.789, wires=0),
        "Toffoli": qml.Toffoli(wires=[0, 1, 2]),
        "PhaseShift": qml.PhaseShift(2.133, wires=0),
        "ControlledPhaseShift": qml.ControlledPhaseShift(1.777, wires=[0, 2]),
        "CPhase": qml.CPhase(1.777, wires=[0, 2]),
        "MultiRZ": qml.MultiRZ(0.112, wires=[1, 2, 3]),
        "CRX": qml.CRX(0.836, wires=[2, 3]),
        "CRY": qml.CRY(0.721, wires=[2, 3]),
        "CRZ": qml.CRZ(0.554, wires=[2, 3]),
        "Hadamard": qml.Hadamard(wires=0),
        "PauliX": qml.PauliX(wires=0),
        "PauliY": qml.PauliY(wires=0),
        "PauliZ": qml.PauliZ(wires=0),
        "CRot": qml.CRot(0.123, 0.456, 0.789, wires=[0, 1]),
        "DiagonalQubitUnitary": qml.DiagonalQubitUnitary(np.array([1.0, 1.0j]), wires=1),
        "ControlledQubitUnitary": qml.ControlledQubitUnitary(
            np.eye(2) * 1j, wires=[0], control_wires=[2]
        ),
        "MultiControlledX": qml.MultiControlledX(wires=(0, 1, 2), control_values="01"),
        "SingleExcitation": qml.SingleExcitation(0.123, wires=[0, 3]),
        "SingleExcitationPlus": qml.SingleExcitationPlus(0.123, wires=[0, 3]),
        "SingleExcitationMinus": qml.SingleExcitationMinus(0.123, wires=[0, 3]),
        "DoubleExcitation": qml.DoubleExcitation(0.123, wires=[0, 1, 2, 3]),
        "DoubleExcitationPlus": qml.DoubleExcitationPlus(0.123, wires=[0, 1, 2, 3]),
        "DoubleExcitationMinus": qml.DoubleExcitationMinus(0.123, wires=[0, 1, 2, 3]),
        "QFT": qml.QFT(wires=0),
        "QubitSum": qml.QubitSum(wires=[0, 1, 2]),
        "QubitCarry": qml.QubitCarry(wires=[0, 1, 2, 3]),
        "QubitUnitary": qml.QubitUnitary(np.eye(2) * 1j, wires=0),
    }
    return ops_list.get(op_name)
Example #17
0
def circuit_decomposed(weights):
    qml.PauliRot(weights[0], "XI", wires=[0, 1])
    qml.PauliRot(weights[1], "YI", wires=[0, 1])
    qml.PauliRot(weights[2], "IX", wires=[0, 1])
    qml.PauliRot(weights[3], "IY", wires=[0, 1])
    qml.PauliRot(weights[4], "XX", wires=[0, 1])
    qml.PauliRot(weights[5], "XY", wires=[0, 1])
    return qml.expval(qml.PauliZ(0))
Example #18
0
    def test_PauliRot_wire_as_int(self):
        """Test that passing a single wire as an integer works."""

        theta = 0.4
        op = qml.PauliRot(theta, "Z", wires=0)
        decomp_ops = op.decomposition(theta, "Z", wires=0)

        assert np.allclose(op.eigvals, np.array([np.exp(-1j * theta / 2), np.exp(1j * theta / 2)]))
        assert np.allclose(op.matrix, np.diag([np.exp(-1j * theta / 2), np.exp(1j * theta / 2)]))

        assert len(decomp_ops) == 1

        assert decomp_ops[0].name == "MultiRZ"

        assert decomp_ops[0].wires == Wires([0])
        assert decomp_ops[0].data[0] == theta
Example #19
0
def ArbitraryStatePreparation(weights, wires):
    """Implements an arbitrary state preparation on the specified wires.

    An arbitrary state on :math:`n` wires is parametrized by :math:`2^{n+1} - 2`
    independent real parameters. This templates uses Pauli word rotations to
    parametrize the unitary.

    **Example**

    ArbitraryStatePreparation can be used to train state preparations,
    for example using a circuit with some measurement observable ``H``:

    .. code-block:: python

        dev = qml.device("default.qubit", wires=4)

        @qml.qnode(dev)
        def vqe(weights):
            qml.ArbitraryStatePreparations(weights, wires=[0, 1, 2, 3])

            return qml.expval(qml.Hermitian(H, wires=[0, 1, 2, 3]))

    Args:
        weights (array[float]): The angles of the Pauli word rotations, needs to have length :math:`2^(n+1) - 2`
            where :math:`n` is the number of wires the template acts upon.
        wires (Iterable or Wires): Wires that the template acts on. Accepts an iterable of numbers or strings, or
            a Wires object.
    """

    wires = Wires(wires)

    n_wires = len(wires)
    expected_shape = (2**(n_wires + 1) - 2, )
    check_shape(
        weights,
        expected_shape,
        msg="'weights' must be of shape {}; got {}."
        "".format(expected_shape, get_shape(weights)),
    )

    wires = wires.tolist()  # Todo: remove when ops take Wires object

    for i, pauli_word in enumerate(_state_preparation_pauli_words(len(wires))):
        qml.PauliRot(weights[i], pauli_word, wires=wires)
Example #20
0
class TestApproxTimeEvolution:
    """Tests for the ApproxTimeEvolution template from the pennylane.templates.subroutine module."""

    def test_hamiltonian_error(self):
        """Tests if the correct error is thrown when hamiltonian is not a pennylane.Hamiltonian object"""

        n_wires = 2
        dev = qml.device("default.qubit", wires=n_wires)

        hamiltonian = np.array([[1, 1], [1, 1]])

        @qml.qnode(dev)
        def circuit():
            ApproxTimeEvolution(hamiltonian, 2, 3)
            return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_wires)]

        with pytest.raises(ValueError, match="hamiltonian must be of type pennylane.Hamiltonian"):
            circuit()

    def test_n_error(self):
        """Tests if the correct error is thrown when n is not an integer"""

        n_wires = 2
        dev = qml.device("default.qubit", wires=n_wires)

        hamiltonian = qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)])
        n = 1.37

        @qml.qnode(dev)
        def circuit():
            ApproxTimeEvolution(hamiltonian, 2, n)
            return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_wires)]

        with pytest.raises(ValueError, match="n must be of type int"):
            circuit()

    @pytest.mark.parametrize(
        ("hamiltonian", "output"),
        [
            (qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.Hadamard(0)]), "Hadamard"),
            (
                qml.Hamiltonian(
                    [1, 1],
                    [qml.PauliX(0) @ qml.Hermitian(np.array([[1, 1], [1, 1]]), 1), qml.PauliX(0)],
                ),
                "Hermitian",
            ),
        ],
    )
    def test_non_pauli_error(self, hamiltonian, output):
        """Tests if the correct errors are thrown when the user attempts to input a matrix with non-Pauli terms"""

        n_wires = 2
        dev = qml.device("default.qubit", wires=n_wires)

        @qml.qnode(dev)
        def circuit():
            ApproxTimeEvolution(hamiltonian, 2, 3)
            return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_wires)]

        with pytest.raises(
            ValueError, match="hamiltonian must be written in terms of Pauli matrices"
        ):
            circuit()

    @pytest.mark.parametrize(
        ("time", "hamiltonian", "steps", "gates"),
        [
            (
                2,
                qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)]),
                2,
                [
                    qml.PauliRot(2.0, "X", wires=[0]),
                    qml.PauliRot(2.0, "X", wires=[1]),
                    qml.PauliRot(2.0, "X", wires=[0]),
                    qml.PauliRot(2.0, "X", wires=[1]),
                ],
            ),
            (
                2,
                qml.Hamiltonian([2, 0.5], [qml.PauliX("a"), qml.PauliZ("b") @ qml.PauliX("a")]),
                2,
                [
                    qml.PauliRot(4.0, "X", wires=["a"]),
                    qml.PauliRot(1.0, "ZX", wires=["b", "a"]),
                    qml.PauliRot(4.0, "X", wires=["a"]),
                    qml.PauliRot(1.0, "ZX", wires=["b", "a"]),
                ],
            ),
            (
                2,
                qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.Identity(0) @ qml.Identity(1)]),
                2,
                [qml.PauliRot(2.0, "X", wires=[0]), qml.PauliRot(2.0, "X", wires=[0])],
            ),
            (
                2,
                qml.Hamiltonian(
                    [2, 0.5, 0.5],
                    [
                        qml.PauliX("a"),
                        qml.PauliZ(-15) @ qml.PauliX("a"),
                        qml.Identity(0) @ qml.PauliY(-15),
                    ],
                ),
                1,
                [
                    qml.PauliRot(8.0, "X", wires=["a"]),
                    qml.PauliRot(2.0, "ZX", wires=[-15, "a"]),
                    qml.PauliRot(2.0, "IY", wires=[0, -15]),
                ],
            ),
        ],
    )
    def test_evolution_operations(self, time, hamiltonian, steps, gates):
        """Tests that the sequence of gates implemented in the ApproxTimeEvolution template is correct"""

        n_wires = 2

        with qml._queuing.OperationRecorder() as rec:
            ApproxTimeEvolution(hamiltonian, time, steps)

        for i, gate in enumerate(rec.operations):
            prep = [gate.parameters, gate.wires]
            target = [gates[i].parameters, gates[i].wires]

            assert prep == target

    @pytest.mark.parametrize(
        ("time", "hamiltonian", "steps", "expectation"),
        [
            (np.pi, qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)]), 2, [1.0, 1.0]),
            (
                np.pi / 2,
                qml.Hamiltonian([0.5, 1], [qml.PauliY(0), qml.Identity(0) @ qml.PauliX(1)]),
                1,
                [0.0, -1.0],
            ),
            (
                np.pi / 4,
                qml.Hamiltonian(
                    [1, 1, 1], [qml.PauliX(0), qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(1)]
                ),
                1,
                [0.0, 0.0],
            ),
            (
                1,
                qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)]),
                2,
                [-0.41614684, -0.41614684],
            ),
            (
                2,
                qml.Hamiltonian(
                    [1, 1, 1, 1],
                    [qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliY(1)],
                ),
                2,
                [-0.87801124, 0.51725747],
            ),
        ],
    )
    def test_evolution_output(self, time, hamiltonian, steps, expectation):
        """Tests that the output from the ApproxTimeEvolution template is correct"""

        n_wires = 2
        dev = qml.device("default.qubit", wires=n_wires)

        @qml.qnode(dev)
        def circuit():
            ApproxTimeEvolution(hamiltonian, time, steps)
            return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_wires)]

        assert np.allclose(circuit(), expectation)
Example #21
0
class TestLayers:
    """Tests that the cost and mixer layers are being constructed properly"""
    def test_mixer_layer_errors(self):
        """Tests that the mixer layer is throwing the correct errors"""

        hamiltonian = [[1, 1], [1, 1]]

        with pytest.raises(
                ValueError,
                match=r"hamiltonian must be of type pennylane.Hamiltonian"):
            qaoa.mixer_layer(0.1, hamiltonian)

    def test_cost_layer_errors(self):
        """Tests that the cost layer is throwing the correct errors"""

        hamiltonian = [[1, 1], [1, 1]]

        with pytest.raises(
                ValueError,
                match=r"hamiltonian must be of type pennylane.Hamiltonian"):
            qaoa.cost_layer(0.1, hamiltonian)

        hamiltonian = qml.Hamiltonian([1, 1], [qml.PauliZ(0), qml.PauliX(1)])

        with pytest.raises(
                ValueError,
                match=
                r"hamiltonian must be written only in terms of PauliZ and Identity gates"
        ):
            qaoa.cost_layer(0.1, hamiltonian)

    @pytest.mark.parametrize(
        ("mixer", "gates"), [[
            qml.Hamiltonian([1, 1],
                            [qml.PauliX(0), qml.PauliX(1)]),
            [qml.PauliRot(2, "X", wires=[0]),
             qml.PauliRot(2, "X", wires=[1])]
        ],
                             [
                                 qaoa.xy_mixer(Graph([(0, 1), (1, 2),
                                                      (2, 0)])),
                                 [
                                     qml.PauliRot(1, "XX", wires=[0, 1]),
                                     qml.PauliRot(1, "YY", wires=[0, 1]),
                                     qml.PauliRot(1, "XX", wires=[0, 2]),
                                     qml.PauliRot(1, "YY", wires=[0, 2]),
                                     qml.PauliRot(1, "XX", wires=[1, 2]),
                                     qml.PauliRot(1, "YY", wires=[1, 2])
                                 ]
                             ]])
    def test_mixer_layer_output(self, mixer, gates):
        """Tests that the gates of the mixer layer are correct"""

        alpha = 1

        with qml._queuing.OperationRecorder() as rec:
            qaoa.mixer_layer(alpha, mixer)

        for i, j in zip(rec.operations, gates):

            prep = [i.name, i.parameters, i.wires]
            target = [j.name, j.parameters, j.wires]

            assert prep == target

    @pytest.mark.parametrize(
        ("cost", "gates"), [[
            qml.Hamiltonian([1, 1],
                            [qml.PauliZ(0), qml.PauliZ(1)]),
            [qml.PauliRot(2, "Z", wires=[0]),
             qml.PauliRot(2, "Z", wires=[1])]
        ],
                            [
                                qaoa.maxcut(Graph([(0, 1), (1, 2),
                                                   (2, 0)]))[0],
                                [
                                    qml.PauliRot(1, "ZZ", wires=[0, 1]),
                                    qml.PauliRot(1, "ZZ", wires=[0, 2]),
                                    qml.PauliRot(1, "ZZ", wires=[1, 2])
                                ]
                            ]])
    def test_cost_layer_output(self, cost, gates):
        """Tests that the gates of the cost layer is correct"""

        gamma = 1

        with qml._queuing.OperationRecorder() as rec:
            qaoa.cost_layer(gamma, cost)

        for i, j in zip(rec.operations, gates):
            prep = [i.name, i.parameters, i.wires]
            target = [j.name, j.parameters, j.wires]

        assert prep == target
Example #22
0
        def circuit(theta):
            qml.PauliRot(theta, "XX", wires=[0, 1])

            return qml.expval(qml.PauliZ(0))
Example #23
0
    "T": qml.T(wires=[0]),
    "SX": qml.SX(wires=[0]),
    "Toffoli": qml.Toffoli(wires=[0, 1, 2]),
    "QFT": qml.templates.QFT(wires=[0, 1, 2]),
    "IsingXX": qml.IsingXX(0, wires=[0, 1]),
    "IsingYY": qml.IsingYY(0, wires=[0, 1]),
    "IsingZZ": qml.IsingZZ(0, wires=[0, 1]),
    "SingleExcitation": qml.SingleExcitation(0, wires=[0, 1]),
    "SingleExcitationPlus": qml.SingleExcitationPlus(0, wires=[0, 1]),
    "SingleExcitationMinus": qml.SingleExcitationMinus(0, wires=[0, 1]),
    "DoubleExcitation": qml.DoubleExcitation(0, wires=[0, 1, 2, 3]),
    "DoubleExcitationPlus": qml.DoubleExcitationPlus(0, wires=[0, 1, 2, 3]),
    "DoubleExcitationMinus": qml.DoubleExcitationMinus(0, wires=[0, 1, 2, 3]),
    "QubitCarry": qml.QubitCarry(wires=[0, 1, 2, 3]),
    "QubitSum": qml.QubitSum(wires=[0, 1, 2]),
    "PauliRot": qml.PauliRot(0, "XXYY", wires=[0, 1, 2, 3]),
    "U1": qml.U1(0, wires=0),
    "U2": qml.U2(0, 0, wires=0),
    "U3": qml.U3(0, 0, 0, wires=0),
    "SISWAP": qml.SISWAP(wires=[0, 1]),
}

all_ops = ops.keys()

# All qubit operations should be available to test in the device test suite
all_available_ops = qml.ops._qubit__ops__.copy()  # pylint: disable=protected-access
all_available_ops.remove("CPhase")  # CPhase is an alias of ControlledPhaseShift
all_available_ops.remove("SQISW")  # SQISW is an alias of SISWAP
all_available_ops.add("QFT")  # QFT was recently moved to being a template, but let's keep it here

if not set(all_ops) == all_available_ops:
class TestRepresentationResolver:
    """Test the RepresentationResolver class."""
    @pytest.mark.parametrize(
        "list,element,index,list_after",
        [
            ([1, 2, 3], 2, 1, [1, 2, 3]),
            ([1, 2, 2, 3], 2, 1, [1, 2, 2, 3]),
            ([1, 2, 3], 4, 3, [1, 2, 3, 4]),
        ],
    )
    def test_index_of_array_or_append(self, list, element, index, list_after):
        """Test the method index_of_array_or_append."""

        assert RepresentationResolver.index_of_array_or_append(element,
                                                               list) == index
        assert list == list_after

    @pytest.mark.parametrize(
        "par,expected",
        [
            (3, "3"),
            (5.236422, "5.24"),
        ],
    )
    def test_single_parameter_representation(self,
                                             unicode_representation_resolver,
                                             par, expected):
        """Test that single parameters are properly resolved."""
        assert unicode_representation_resolver.single_parameter_representation(
            par) == expected

    @pytest.mark.parametrize(
        "op,wire,target",
        [
            (qml.PauliX(wires=[1]), 1, "X"),
            (qml.CNOT(wires=[0, 1]), 1, "X"),
            (qml.CNOT(wires=[0, 1]), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]), 1, "X"),
            (qml.Toffoli(wires=[0, 2, 1]), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]), 2, "C"),
            (qml.CSWAP(wires=[0, 2, 1]), 1, "SWAP"),
            (qml.CSWAP(wires=[0, 2, 1]), 2, "SWAP"),
            (qml.CSWAP(wires=[0, 2, 1]), 0, "C"),
            (qml.PauliY(wires=[1]), 1, "Y"),
            (qml.PauliZ(wires=[1]), 1, "Z"),
            (qml.CZ(wires=[0, 1]), 1, "Z"),
            (qml.CZ(wires=[0, 1]), 0, "C"),
            (qml.Identity(wires=[1]), 1, "I"),
            (qml.Hadamard(wires=[1]), 1, "H"),
            (qml.PauliRot(3.14, "XX", wires=[0, 1]), 1, "RX(3.14)"),
            (qml.PauliRot(3.14, "YZ", wires=[0, 1]), 1, "RZ(3.14)"),
            (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4
                                                ]), 0, "RI(3.14)"),
            (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4
                                                ]), 1, "RX(3.14)"),
            (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4
                                                ]), 2, "RY(3.14)"),
            (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4
                                                ]), 3, "RZ(3.14)"),
            (qml.PauliRot(3.14, "IXYZI", wires=[0, 1, 2, 3, 4
                                                ]), 4, "RI(3.14)"),
            (qml.MultiRZ(3.14, wires=[0, 1]), 0, "RZ(3.14)"),
            (qml.MultiRZ(3.14, wires=[0, 1]), 1, "RZ(3.14)"),
            (qml.CRX(3.14, wires=[0, 1]), 1, "RX(3.14)"),
            (qml.CRX(3.14, wires=[0, 1]), 0, "C"),
            (qml.CRY(3.14, wires=[0, 1]), 1, "RY(3.14)"),
            (qml.CRY(3.14, wires=[0, 1]), 0, "C"),
            (qml.CRZ(3.14, wires=[0, 1]), 1, "RZ(3.14)"),
            (qml.CRZ(3.14, wires=[0, 1]), 0, "C"),
            (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1
                                               ]), 1, "Rot(3.14, 2.14, 1.14)"),
            (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1]), 0, "C"),
            (qml.PhaseShift(3.14, wires=[0]), 0, "Rϕ(3.14)"),
            (qml.Beamsplitter(1, 2, wires=[0, 1]), 1, "BS(1, 2)"),
            (qml.Beamsplitter(1, 2, wires=[0, 1]), 0, "BS(1, 2)"),
            (qml.Squeezing(1, 2, wires=[1]), 1, "S(1, 2)"),
            (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 1, "S(1, 2)"),
            (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 0, "S(1, 2)"),
            (qml.Displacement(1, 2, wires=[1]), 1, "D(1, 2)"),
            (qml.NumberOperator(wires=[1]), 1, "n"),
            (qml.Rotation(3.14, wires=[1]), 1, "R(3.14)"),
            (qml.ControlledAddition(3.14, wires=[0, 1]), 1, "X(3.14)"),
            (qml.ControlledAddition(3.14, wires=[0, 1]), 0, "C"),
            (qml.ControlledPhase(3.14, wires=[0, 1]), 1, "Z(3.14)"),
            (qml.ControlledPhase(3.14, wires=[0, 1]), 0, "C"),
            (qml.ThermalState(3, wires=[1]), 1, "Thermal(3)"),
            (
                qml.GaussianState(np.array([[2, 0], [0, 2]]),
                                  np.array([1, 2]),
                                  wires=[1]),
                1,
                "Gaussian(M0,M1)",
            ),
            (qml.QuadraticPhase(3.14, wires=[1]), 1, "P(3.14)"),
            (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"),
            (qml.S(wires=[2]), 2, "S"),
            (qml.T(wires=[2]), 2, "T"),
            (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"),
            (qml.RY(3.14, wires=[1]), 1, "RY(3.14)"),
            (qml.RZ(3.14, wires=[1]), 1, "RZ(3.14)"),
            (qml.Rot(3.14, 2.14, 1.14, wires=[1]), 1, "Rot(3.14, 2.14, 1.14)"),
            (qml.U1(3.14, wires=[1]), 1, "U1(3.14)"),
            (qml.U2(3.14, 2.14, wires=[1]), 1, "U2(3.14, 2.14)"),
            (qml.U3(3.14, 2.14, 1.14, wires=[1]), 1, "U3(3.14, 2.14, 1.14)"),
            (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 1, "|0⟩"),
            (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 2, "|1⟩"),
            (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 3, "|0⟩"),
            (qml.QubitStateVector(np.array([0, 1, 0, 0]),
                                  wires=[1, 2]), 1, "QubitStateVector(M0)"),
            (qml.QubitStateVector(np.array([0, 1, 0, 0]),
                                  wires=[1, 2]), 2, "QubitStateVector(M0)"),
            (qml.QubitUnitary(np.eye(2), wires=[1]), 1, "U0"),
            (qml.QubitUnitary(np.eye(4), wires=[1, 2]), 2, "U0"),
            (qml.Kerr(3.14, wires=[1]), 1, "Kerr(3.14)"),
            (qml.CrossKerr(3.14, wires=[1, 2]), 1, "CrossKerr(3.14)"),
            (qml.CrossKerr(3.14, wires=[1, 2]), 2, "CrossKerr(3.14)"),
            (qml.CubicPhase(3.14, wires=[1]), 1, "V(3.14)"),
            (qml.InterferometerUnitary(
                np.eye(4), wires=[1, 3]), 1, "InterferometerUnitary(M0)"),
            (qml.InterferometerUnitary(
                np.eye(4), wires=[1, 3]), 3, "InterferometerUnitary(M0)"),
            (qml.CatState(3.14, 2.14, 1,
                          wires=[1]), 1, "CatState(3.14, 2.14, 1)"),
            (qml.CoherentState(3.14, 2.14,
                               wires=[1]), 1, "CoherentState(3.14, 2.14)"),
            (
                qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)),
                                      wires=[1, 2]),
                1,
                "FockDensityMatrix(M0)",
            ),
            (
                qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)),
                                      wires=[1, 2]),
                2,
                "FockDensityMatrix(M0)",
            ),
            (
                qml.DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14, wires=[1]),
                1,
                "DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14)",
            ),
            (qml.FockState(7, wires=[1]), 1, "|7⟩"),
            (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3
                                                             ]), 1, "|4⟩"),
            (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3
                                                             ]), 2, "|5⟩"),
            (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3
                                                             ]), 3, "|7⟩"),
            (qml.SqueezedState(3.14, 2.14,
                               wires=[1]), 1, "SqueezedState(3.14, 2.14)"),
            (qml.Hermitian(np.eye(4), wires=[1, 2]), 1, "H0"),
            (qml.Hermitian(np.eye(4), wires=[1, 2]), 2, "H0"),
            (qml.X(wires=[1]), 1, "x"),
            (qml.P(wires=[1]), 1, "p"),
            (qml.FockStateProjector(np.array([4, 5, 7]),
                                    wires=[1, 2, 3]), 1, "|4,5,7╳4,5,7|"),
            (
                qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1]),
                2,
                "1+2x₀-1.3x₁+6p₁",
            ),
            (
                qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                     [-1.3, 4.5, 2.3]]),
                           wires=[1]),
                1,
                "1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀",
            ),
            (
                qml.PolyXP(
                    np.array([
                        [1.2, 2.3, 4.5, 0, 0],
                        [-1.2, 1.2, -1.5, 0, 0],
                        [-1.3, 4.5, 2.3, 0, 0],
                        [0, 2.6, 0, 0, 0],
                        [0, 0, 0, -4.7, -1.0],
                    ]),
                    wires=[1],
                ),
                1,
                "1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀+2.6x₀x₁-p₁²-4.7x₁p₁",
            ),
            (qml.QuadOperator(3.14, wires=[1]), 1, "cos(3.14)x+sin(3.14)p"),
            (qml.PauliX(wires=[1]).inv(), 1, "X⁻¹"),
            (qml.CNOT(wires=[0, 1]).inv(), 1, "X⁻¹"),
            (qml.CNOT(wires=[0, 1]).inv(), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]).inv(), 1, "X⁻¹"),
            (qml.Toffoli(wires=[0, 2, 1]).inv(), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]).inv(), 2, "C"),
            (qml.measure.sample(wires=[0, 1]), 0,
             "basis"),  # not providing an observable in
            (qml.measure.sample(wires=[0, 1]), 1,
             "basis"),  # sample gets displayed as raw
            (two_wire_quantum_tape(), 0, "QuantumTape:T0"),
            (two_wire_quantum_tape(), 1, "QuantumTape:T0"),
        ],
    )
    def test_operator_representation_unicode(self,
                                             unicode_representation_resolver,
                                             op, wire, target):
        """Test that an Operator instance is properly resolved."""
        assert unicode_representation_resolver.operator_representation(
            op, wire) == target

    @pytest.mark.parametrize(
        "op,wire,target",
        [
            (qml.PauliX(wires=[1]), 1, "X"),
            (qml.CNOT(wires=[0, 1]), 1, "X"),
            (qml.CNOT(wires=[0, 1]), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]), 1, "X"),
            (qml.Toffoli(wires=[0, 2, 1]), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]), 2, "C"),
            (qml.CSWAP(wires=[0, 2, 1]), 1, "SWAP"),
            (qml.CSWAP(wires=[0, 2, 1]), 2, "SWAP"),
            (qml.CSWAP(wires=[0, 2, 1]), 0, "C"),
            (qml.PauliY(wires=[1]), 1, "Y"),
            (qml.PauliZ(wires=[1]), 1, "Z"),
            (qml.CZ(wires=[0, 1]), 1, "Z"),
            (qml.CZ(wires=[0, 1]), 0, "C"),
            (qml.Identity(wires=[1]), 1, "I"),
            (qml.Hadamard(wires=[1]), 1, "H"),
            (qml.CRX(3.14, wires=[0, 1]), 1, "RX(3.14)"),
            (qml.CRX(3.14, wires=[0, 1]), 0, "C"),
            (qml.CRY(3.14, wires=[0, 1]), 1, "RY(3.14)"),
            (qml.CRY(3.14, wires=[0, 1]), 0, "C"),
            (qml.CRZ(3.14, wires=[0, 1]), 1, "RZ(3.14)"),
            (qml.CRZ(3.14, wires=[0, 1]), 0, "C"),
            (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1
                                               ]), 1, "Rot(3.14, 2.14, 1.14)"),
            (qml.CRot(3.14, 2.14, 1.14, wires=[0, 1]), 0, "C"),
            (qml.PhaseShift(3.14, wires=[0]), 0, "Rϕ(3.14)"),
            (qml.Beamsplitter(1, 2, wires=[0, 1]), 1, "BS(1, 2)"),
            (qml.Beamsplitter(1, 2, wires=[0, 1]), 0, "BS(1, 2)"),
            (qml.Squeezing(1, 2, wires=[1]), 1, "S(1, 2)"),
            (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 1, "S(1, 2)"),
            (qml.TwoModeSqueezing(1, 2, wires=[0, 1]), 0, "S(1, 2)"),
            (qml.Displacement(1, 2, wires=[1]), 1, "D(1, 2)"),
            (qml.NumberOperator(wires=[1]), 1, "n"),
            (qml.Rotation(3.14, wires=[1]), 1, "R(3.14)"),
            (qml.ControlledAddition(3.14, wires=[0, 1]), 1, "X(3.14)"),
            (qml.ControlledAddition(3.14, wires=[0, 1]), 0, "C"),
            (qml.ControlledPhase(3.14, wires=[0, 1]), 1, "Z(3.14)"),
            (qml.ControlledPhase(3.14, wires=[0, 1]), 0, "C"),
            (qml.ThermalState(3, wires=[1]), 1, "Thermal(3)"),
            (
                qml.GaussianState(np.array([[2, 0], [0, 2]]),
                                  np.array([1, 2]),
                                  wires=[1]),
                1,
                "Gaussian(M0,M1)",
            ),
            (qml.QuadraticPhase(3.14, wires=[1]), 1, "P(3.14)"),
            (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"),
            (qml.S(wires=[2]), 2, "S"),
            (qml.T(wires=[2]), 2, "T"),
            (qml.RX(3.14, wires=[1]), 1, "RX(3.14)"),
            (qml.RY(3.14, wires=[1]), 1, "RY(3.14)"),
            (qml.RZ(3.14, wires=[1]), 1, "RZ(3.14)"),
            (qml.Rot(3.14, 2.14, 1.14, wires=[1]), 1, "Rot(3.14, 2.14, 1.14)"),
            (qml.U1(3.14, wires=[1]), 1, "U1(3.14)"),
            (qml.U2(3.14, 2.14, wires=[1]), 1, "U2(3.14, 2.14)"),
            (qml.U3(3.14, 2.14, 1.14, wires=[1]), 1, "U3(3.14, 2.14, 1.14)"),
            (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 1, "|0>"),
            (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 2, "|1>"),
            (qml.BasisState(np.array([0, 1, 0]), wires=[1, 2, 3]), 3, "|0>"),
            (qml.QubitStateVector(np.array([0, 1, 0, 0]),
                                  wires=[1, 2]), 1, "QubitStateVector(M0)"),
            (qml.QubitStateVector(np.array([0, 1, 0, 0]),
                                  wires=[1, 2]), 2, "QubitStateVector(M0)"),
            (qml.QubitUnitary(np.eye(2), wires=[1]), 1, "U0"),
            (qml.QubitUnitary(np.eye(4), wires=[1, 2]), 2, "U0"),
            (qml.Kerr(3.14, wires=[1]), 1, "Kerr(3.14)"),
            (qml.CrossKerr(3.14, wires=[1, 2]), 1, "CrossKerr(3.14)"),
            (qml.CrossKerr(3.14, wires=[1, 2]), 2, "CrossKerr(3.14)"),
            (qml.CubicPhase(3.14, wires=[1]), 1, "V(3.14)"),
            (qml.InterferometerUnitary(
                np.eye(4), wires=[1, 3]), 1, "InterferometerUnitary(M0)"),
            (qml.InterferometerUnitary(
                np.eye(4), wires=[1, 3]), 3, "InterferometerUnitary(M0)"),
            (qml.CatState(3.14, 2.14, 1,
                          wires=[1]), 1, "CatState(3.14, 2.14, 1)"),
            (qml.CoherentState(3.14, 2.14,
                               wires=[1]), 1, "CoherentState(3.14, 2.14)"),
            (
                qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)),
                                      wires=[1, 2]),
                1,
                "FockDensityMatrix(M0)",
            ),
            (
                qml.FockDensityMatrix(np.kron(np.eye(4), np.eye(4)),
                                      wires=[1, 2]),
                2,
                "FockDensityMatrix(M0)",
            ),
            (
                qml.DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14, wires=[1]),
                1,
                "DisplacedSqueezedState(3.14, 2.14, 1.14, 0.14)",
            ),
            (qml.FockState(7, wires=[1]), 1, "|7>"),
            (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3
                                                             ]), 1, "|4>"),
            (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3
                                                             ]), 2, "|5>"),
            (qml.FockStateVector(np.array([4, 5, 7]), wires=[1, 2, 3
                                                             ]), 3, "|7>"),
            (qml.SqueezedState(3.14, 2.14,
                               wires=[1]), 1, "SqueezedState(3.14, 2.14)"),
            (qml.Hermitian(np.eye(4), wires=[1, 2]), 1, "H0"),
            (qml.Hermitian(np.eye(4), wires=[1, 2]), 2, "H0"),
            (qml.X(wires=[1]), 1, "x"),
            (qml.P(wires=[1]), 1, "p"),
            (qml.FockStateProjector(np.array([4, 5, 7]),
                                    wires=[1, 2, 3]), 1, "|4,5,7X4,5,7|"),
            (
                qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1]),
                2,
                "1+2x_0-1.3x_1+6p_1",
            ),
            (
                qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                     [-1.3, 4.5, 2.3]]),
                           wires=[1]),
                1,
                "1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0",
            ),
            (
                qml.PolyXP(
                    np.array([
                        [1.2, 2.3, 4.5, 0, 0],
                        [-1.2, 1.2, -1.5, 0, 0],
                        [-1.3, 4.5, 2.3, 0, 0],
                        [0, 2.6, 0, 0, 0],
                        [0, 0, 0, -4.7, 0],
                    ]),
                    wires=[1],
                ),
                1,
                "1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0+2.6x_0x_1-4.7x_1p_1",
            ),
            (qml.QuadOperator(3.14, wires=[1]), 1, "cos(3.14)x+sin(3.14)p"),
            (qml.QuadOperator(3.14, wires=[1]), 1, "cos(3.14)x+sin(3.14)p"),
            (qml.PauliX(wires=[1]).inv(), 1, "X^-1"),
            (qml.CNOT(wires=[0, 1]).inv(), 1, "X^-1"),
            (qml.CNOT(wires=[0, 1]).inv(), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]).inv(), 1, "X^-1"),
            (qml.Toffoli(wires=[0, 2, 1]).inv(), 0, "C"),
            (qml.Toffoli(wires=[0, 2, 1]).inv(), 2, "C"),
            (qml.measure.sample(wires=[0, 1]), 0,
             "basis"),  # not providing an observable in
            (qml.measure.sample(wires=[0, 1]), 1,
             "basis"),  # sample gets displayed as raw
            (two_wire_quantum_tape(), 0, "QuantumTape:T0"),
            (two_wire_quantum_tape(), 1, "QuantumTape:T0"),
        ],
    )
    def test_operator_representation_ascii(self, ascii_representation_resolver,
                                           op, wire, target):
        """Test that an Operator instance is properly resolved."""
        assert ascii_representation_resolver.operator_representation(
            op, wire) == target

    @pytest.mark.parametrize(
        "obs,wire,target",
        [
            (qml.expval(qml.PauliX(wires=[1])), 1, "⟨X⟩"),
            (qml.expval(qml.PauliY(wires=[1])), 1, "⟨Y⟩"),
            (qml.expval(qml.PauliZ(wires=[1])), 1, "⟨Z⟩"),
            (qml.expval(qml.Hadamard(wires=[1])), 1, "⟨H⟩"),
            (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "⟨H0⟩"),
            (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "⟨H0⟩"),
            (qml.expval(qml.NumberOperator(wires=[1])), 1, "⟨n⟩"),
            (qml.expval(qml.X(wires=[1])), 1, "⟨x⟩"),
            (qml.expval(qml.P(wires=[1])), 1, "⟨p⟩"),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])),
                1,
                "⟨|4,5,7╳4,5,7|⟩",
            ),
            (
                qml.expval(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1
                                                                           ])),
                2,
                "⟨1+2x₀-1.3x₁+6p₁⟩",
            ),
            (
                qml.expval(
                    qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                         [-1.3, 4.5, 2.3]]),
                               wires=[1])),
                1,
                "⟨1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀⟩",
            ),
            (qml.expval(qml.QuadOperator(
                3.14, wires=[1])), 1, "⟨cos(3.14)x+sin(3.14)p⟩"),
            (qml.var(qml.PauliX(wires=[1])), 1, "Var[X]"),
            (qml.var(qml.PauliY(wires=[1])), 1, "Var[Y]"),
            (qml.var(qml.PauliZ(wires=[1])), 1, "Var[Z]"),
            (qml.var(qml.Hadamard(wires=[1])), 1, "Var[H]"),
            (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "Var[H0]"),
            (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "Var[H0]"),
            (qml.var(qml.NumberOperator(wires=[1])), 1, "Var[n]"),
            (qml.var(qml.X(wires=[1])), 1, "Var[x]"),
            (qml.var(qml.P(wires=[1])), 1, "Var[p]"),
            (
                qml.var(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])),
                1,
                "Var[|4,5,7╳4,5,7|]",
            ),
            (
                qml.var(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1])),
                2,
                "Var[1+2x₀-1.3x₁+6p₁]",
            ),
            (
                qml.var(
                    qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                         [-1.3, 4.5, 2.3]]),
                               wires=[1])),
                1,
                "Var[1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀]",
            ),
            (qml.var(qml.QuadOperator(
                3.14, wires=[1])), 1, "Var[cos(3.14)x+sin(3.14)p]"),
            (qml.sample(qml.PauliX(wires=[1])), 1, "Sample[X]"),
            (qml.sample(qml.PauliY(wires=[1])), 1, "Sample[Y]"),
            (qml.sample(qml.PauliZ(wires=[1])), 1, "Sample[Z]"),
            (qml.sample(qml.Hadamard(wires=[1])), 1, "Sample[H]"),
            (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2
                                                        ])), 1, "Sample[H0]"),
            (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2
                                                        ])), 2, "Sample[H0]"),
            (qml.sample(qml.NumberOperator(wires=[1])), 1, "Sample[n]"),
            (qml.sample(qml.X(wires=[1])), 1, "Sample[x]"),
            (qml.sample(qml.P(wires=[1])), 1, "Sample[p]"),
            (
                qml.sample(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])),
                1,
                "Sample[|4,5,7╳4,5,7|]",
            ),
            (
                qml.sample(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1
                                                                           ])),
                2,
                "Sample[1+2x₀-1.3x₁+6p₁]",
            ),
            (
                qml.sample(
                    qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                         [-1.3, 4.5, 2.3]]),
                               wires=[1])),
                1,
                "Sample[1.2+1.1x₀+3.2p₀+1.2x₀²+2.3p₀²+3x₀p₀]",
            ),
            (qml.sample(qml.QuadOperator(
                3.14, wires=[1])), 1, "Sample[cos(3.14)x+sin(3.14)p]"),
            (
                qml.expval(
                    qml.PauliX(wires=[1]) @ qml.PauliY(wires=[2])
                    @ qml.PauliZ(wires=[3])),
                1,
                "⟨X ⊗ Y ⊗ Z⟩",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                1,
                "⟨|4,5,7╳4,5,7| ⊗ x⟩",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                2,
                "⟨|4,5,7╳4,5,7| ⊗ x⟩",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                3,
                "⟨|4,5,7╳4,5,7| ⊗ x⟩",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                4,
                "⟨|4,5,7╳4,5,7| ⊗ x⟩",
            ),
            (
                qml.sample(
                    qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian(
                        np.eye(4), wires=[0, 3])),
                0,
                "Sample[H0 ⊗ H0]",
            ),
            (
                qml.sample(
                    qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian(
                        2 * np.eye(4), wires=[0, 3])),
                0,
                "Sample[H0 ⊗ H1]",
            ),
            (qml.probs([0]), 0, "Probs"),
            (state(), 0, "State"),
        ],
    )
    def test_output_representation_unicode(self,
                                           unicode_representation_resolver,
                                           obs, wire, target):
        """Test that an Observable instance with return type is properly resolved."""
        assert unicode_representation_resolver.output_representation(
            obs, wire) == target

    def test_fallback_output_representation_unicode(
            self, unicode_representation_resolver):
        """Test that an Observable instance with return type is properly resolved."""
        obs = qml.PauliZ(0)
        obs.return_type = "TestReturnType"

        assert unicode_representation_resolver.output_representation(
            obs, 0) == "TestReturnType[Z]"

    @pytest.mark.parametrize(
        "obs,wire,target",
        [
            (qml.expval(qml.PauliX(wires=[1])), 1, "<X>"),
            (qml.expval(qml.PauliY(wires=[1])), 1, "<Y>"),
            (qml.expval(qml.PauliZ(wires=[1])), 1, "<Z>"),
            (qml.expval(qml.Hadamard(wires=[1])), 1, "<H>"),
            (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "<H0>"),
            (qml.expval(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "<H0>"),
            (qml.expval(qml.NumberOperator(wires=[1])), 1, "<n>"),
            (qml.expval(qml.X(wires=[1])), 1, "<x>"),
            (qml.expval(qml.P(wires=[1])), 1, "<p>"),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])),
                1,
                "<|4,5,7X4,5,7|>",
            ),
            (
                qml.expval(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1
                                                                           ])),
                2,
                "<1+2x_0-1.3x_1+6p_1>",
            ),
            (
                qml.expval(
                    qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                         [-1.3, 4.5, 2.3]]),
                               wires=[1])),
                1,
                "<1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0>",
            ),
            (qml.expval(qml.QuadOperator(
                3.14, wires=[1])), 1, "<cos(3.14)x+sin(3.14)p>"),
            (qml.var(qml.PauliX(wires=[1])), 1, "Var[X]"),
            (qml.var(qml.PauliY(wires=[1])), 1, "Var[Y]"),
            (qml.var(qml.PauliZ(wires=[1])), 1, "Var[Z]"),
            (qml.var(qml.Hadamard(wires=[1])), 1, "Var[H]"),
            (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 1, "Var[H0]"),
            (qml.var(qml.Hermitian(np.eye(4), wires=[1, 2])), 2, "Var[H0]"),
            (qml.var(qml.NumberOperator(wires=[1])), 1, "Var[n]"),
            (qml.var(qml.X(wires=[1])), 1, "Var[x]"),
            (qml.var(qml.P(wires=[1])), 1, "Var[p]"),
            (
                qml.var(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])),
                1,
                "Var[|4,5,7X4,5,7|]",
            ),
            (
                qml.var(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1])),
                2,
                "Var[1+2x_0-1.3x_1+6p_1]",
            ),
            (
                qml.var(
                    qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                         [-1.3, 4.5, 2.3]]),
                               wires=[1])),
                1,
                "Var[1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0]",
            ),
            (qml.var(qml.QuadOperator(
                3.14, wires=[1])), 1, "Var[cos(3.14)x+sin(3.14)p]"),
            (qml.sample(qml.PauliX(wires=[1])), 1, "Sample[X]"),
            (qml.sample(qml.PauliY(wires=[1])), 1, "Sample[Y]"),
            (qml.sample(qml.PauliZ(wires=[1])), 1, "Sample[Z]"),
            (qml.sample(qml.Hadamard(wires=[1])), 1, "Sample[H]"),
            (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2
                                                        ])), 1, "Sample[H0]"),
            (qml.sample(qml.Hermitian(np.eye(4), wires=[1, 2
                                                        ])), 2, "Sample[H0]"),
            (qml.sample(qml.NumberOperator(wires=[1])), 1, "Sample[n]"),
            (qml.sample(qml.X(wires=[1])), 1, "Sample[x]"),
            (qml.sample(qml.P(wires=[1])), 1, "Sample[p]"),
            (
                qml.sample(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])),
                1,
                "Sample[|4,5,7X4,5,7|]",
            ),
            (
                qml.sample(qml.PolyXP(np.array([1, 2, 0, -1.3, 6]), wires=[1
                                                                           ])),
                2,
                "Sample[1+2x_0-1.3x_1+6p_1]",
            ),
            (
                qml.sample(
                    qml.PolyXP(np.array([[1.2, 2.3, 4.5], [-1.2, 1.2, -1.5],
                                         [-1.3, 4.5, 2.3]]),
                               wires=[1])),
                1,
                "Sample[1.2+1.1x_0+3.2p_0+1.2x_0^2+2.3p_0^2+3x_0p_0]",
            ),
            (qml.sample(qml.QuadOperator(
                3.14, wires=[1])), 1, "Sample[cos(3.14)x+sin(3.14)p]"),
            (
                qml.expval(
                    qml.PauliX(wires=[1]) @ qml.PauliY(wires=[2])
                    @ qml.PauliZ(wires=[3])),
                1,
                "<X @ Y @ Z>",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                1,
                "<|4,5,7X4,5,7| @ x>",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                2,
                "<|4,5,7X4,5,7| @ x>",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                3,
                "<|4,5,7X4,5,7| @ x>",
            ),
            (
                qml.expval(
                    qml.FockStateProjector(np.array([4, 5, 7]),
                                           wires=[1, 2, 3])
                    @ qml.X(wires=[4])),
                4,
                "<|4,5,7X4,5,7| @ x>",
            ),
            (
                qml.sample(
                    qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian(
                        np.eye(4), wires=[0, 3])),
                0,
                "Sample[H0 @ H0]",
            ),
            (
                qml.sample(
                    qml.Hermitian(np.eye(4), wires=[1, 2]) @ qml.Hermitian(
                        2 * np.eye(4), wires=[0, 3])),
                0,
                "Sample[H0 @ H1]",
            ),
            (qml.probs([0]), 0, "Probs"),
            (state(), 0, "State"),
        ],
    )
    def test_output_representation_ascii(self, ascii_representation_resolver,
                                         obs, wire, target):
        """Test that an Observable instance with return type is properly resolved."""
        assert ascii_representation_resolver.output_representation(
            obs, wire) == target

    def test_element_representation_none(self,
                                         unicode_representation_resolver):
        """Test that element_representation properly handles None."""
        assert unicode_representation_resolver.element_representation(None,
                                                                      0) == ""

    def test_element_representation_str(self, unicode_representation_resolver):
        """Test that element_representation properly handles strings."""
        assert unicode_representation_resolver.element_representation(
            "Test", 0) == "Test"

    def test_element_representation_calls_output(
            self, unicode_representation_resolver):
        """Test that element_representation calls output_representation for returned observables."""

        unicode_representation_resolver.output_representation = Mock()

        obs = qml.sample(qml.PauliX(3))
        wire = 3

        unicode_representation_resolver.element_representation(obs, wire)

        assert unicode_representation_resolver.output_representation.call_args[
            0] == (obs, wire)

    def test_element_representation_calls_operator(
            self, unicode_representation_resolver):
        """Test that element_representation calls operator_representation for all operators that are not returned."""

        unicode_representation_resolver.operator_representation = Mock()

        op = qml.PauliX(3)
        wire = 3

        unicode_representation_resolver.element_representation(op, wire)

        assert unicode_representation_resolver.operator_representation.call_args[
            0] == (op, wire)
Example #25
0
def circuit_decomposed(time):
    qml.PauliRot(time, "X", wires=[0])
    qml.PauliRot(time, "X", wires=[1])
    qml.PauliRot(time, "X", wires=[0])
    qml.PauliRot(time, "X", wires=[1])
    return qml.expval(qml.PauliZ(0))
def circuit_decomposed(weights):
    for i in range(qml.math.shape(weights)[0]):
        qml.PauliRot(weights[i], paulis_two_qubits[i], wires=[0, 1])
    return qml.expval(qml.PauliZ(0))
Example #27
0
def ApproxTimeEvolution(hamiltonian, time, n):
    r"""Applies the Trotterized time-evolution operator for an arbitrary Hamiltonian, expressed in terms
    of Pauli gates.

    The general time-evolution operator for a time-independent Hamiltonian is given by

    .. math:: U(t) \ = \ e^{-i H t},

    for some Hamiltonian of the form:

    .. math:: H \ = \ \displaystyle\sum_{j} H_j.

    Implementing this unitary with a set of quantum gates is difficult, as the terms :math:`H_j` don't
    necessarily commute with one another. However, we are able to exploit the Trotter-Suzuki decomposition formula,

    .. math:: e^{A \ + \ B} \ = \ \lim_{n \to \infty} \Big[ e^{A/n} e^{B/n} \Big]^n,

    to implement an approximation of the time-evolution operator as

    .. math:: U \ \approx \ \displaystyle\prod_{k \ = \ 1}^{n} \displaystyle\prod_{j} e^{-i H_j t / n},

    with the approximation becoming better for larger :math:`n`.
    The circuit implementing this unitary is of the form:

    .. figure:: ../../_static/templates/subroutines/approx_time_evolution.png
        :align: center
        :width: 60%
        :target: javascript:void(0);

    It is also important to note that
    this decomposition is exact for any value of :math:`n` when each term of the Hamiltonian
    commutes with every other term.

    .. note::

       This template uses the :class:`~.PauliRot` operation in order to implement
       exponentiated terms of the input Hamiltonian. This operation only takes
       terms that are explicitly written in terms of products of Pauli matrices (:class:`~.PauliX`,
       :class:`~.PauliY`, :class:`~.PauliZ`, and :class:`~.Identity`).
       Thus, each term in the Hamiltonian must be expressed this way upon input, or else an error will be raised.

    Args:
        hamiltonian (.Hamiltonian): The Hamiltonian defining the
           time-evolution operator.
           The Hamiltonian must be explicitly written
           in terms of products of Pauli gates (:class:`~.PauliX`, :class:`~.PauliY`,
           :class:`~.PauliZ`, and :class:`~.Identity`).
        time (int or float): The time of evolution, namely the parameter :math:`t` in :math:`e^{- i H t}`.
        n (int): The number of Trotter steps used when approximating the time-evolution operator.

    Raises:
        ValueError: if inputs do not have the correct format

    .. UsageDetails::

        The template is used inside a qnode:

        .. code-block:: python

            import pennylane as qml
            from pennylane.templates import ApproxTimeEvolution

            n_wires = 2
            wires = range(n_wires)

            dev = qml.device('default.qubit', wires=n_wires)

            coeffs = [1, 1]
            obs = [qml.PauliX(0), qml.PauliX(1)]
            hamiltonian = qml.Hamiltonian(coeffs, obs)

            @qml.qnode(dev)
            def circuit(time):
                ApproxTimeEvolution(hamiltonian, time, 1)
                return [qml.expval(qml.PauliZ(wires=i)) for i in wires]

        >>> circuit(1)
        [-0.41614684 -0.41614684]
    """

    _preprocess(hamiltonian)

    pauli = {"Identity": "I", "PauliX": "X", "PauliY": "Y", "PauliZ": "Z"}

    theta = []
    pauli_words = []
    wires = []

    for i, term in enumerate(hamiltonian.ops):

        word = ""

        try:
            if isinstance(term.name, str):
                word = pauli[term.name]

            if isinstance(term.name, list):
                word = "".join(pauli[j] for j in term.name)

        except KeyError as error:
            raise ValueError(
                "hamiltonian must be written in terms of Pauli matrices, got {}"
                .format(error)) from error

        # Skips terms composed solely of identities
        if word.count("I") != len(word):

            theta.append((2 * time * hamiltonian.coeffs[i]) / n)
            pauli_words.append(word)
            wires.append(term.wires)

    for i in range(n):

        for j, term in enumerate(pauli_words):
            qml.PauliRot(theta[j], term, wires=wires[j])
Example #28
0
class TestDecomposition:
    """Tests that the template defines the correct decomposition."""

    @pytest.mark.parametrize(
        ("time", "hamiltonian", "steps", "expected_queue"),
        [
            (
                2,
                qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)]),
                2,
                [
                    qml.PauliRot(2.0, "X", wires=[0]),
                    qml.PauliRot(2.0, "X", wires=[1]),
                    qml.PauliRot(2.0, "X", wires=[0]),
                    qml.PauliRot(2.0, "X", wires=[1]),
                ],
            ),
            (
                2,
                qml.Hamiltonian([2, 0.5], [qml.PauliX("a"), qml.PauliZ("b") @ qml.PauliX("a")]),
                2,
                [
                    qml.PauliRot(4.0, "X", wires=["a"]),
                    qml.PauliRot(1.0, "ZX", wires=["b", "a"]),
                    qml.PauliRot(4.0, "X", wires=["a"]),
                    qml.PauliRot(1.0, "ZX", wires=["b", "a"]),
                ],
            ),
            (
                2,
                qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.Identity(0) @ qml.Identity(1)]),
                2,
                [qml.PauliRot(2.0, "X", wires=[0]), qml.PauliRot(2.0, "X", wires=[0])],
            ),
            (
                2,
                qml.Hamiltonian(
                    [2, 0.5, 0.5],
                    [
                        qml.PauliX("a"),
                        qml.PauliZ(-15) @ qml.PauliX("a"),
                        qml.Identity(0) @ qml.PauliY(-15),
                    ],
                ),
                1,
                [
                    qml.PauliRot(8.0, "X", wires=["a"]),
                    qml.PauliRot(2.0, "ZX", wires=[-15, "a"]),
                    qml.PauliRot(2.0, "IY", wires=[0, -15]),
                ],
            ),
        ],
    )
    def test_evolution_operations(self, time, hamiltonian, steps, expected_queue):
        """Tests that the sequence of gates implemented in the ApproxTimeEvolution template is correct"""

        op = qml.ApproxTimeEvolution(hamiltonian, time, steps)
        queue = op.expand().operations

        for expected_gate, gate in zip(expected_queue, queue):
            prep = [gate.parameters, gate.wires]
            target = [expected_gate.parameters, expected_gate.wires]

            assert prep == target

    @pytest.mark.parametrize(
        ("time", "hamiltonian", "steps", "expectation"),
        [
            (np.pi, qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)]), 2, [1.0, 1.0]),
            (
                np.pi / 2,
                qml.Hamiltonian([0.5, 1], [qml.PauliY(0), qml.Identity(0) @ qml.PauliX(1)]),
                1,
                [0.0, -1.0],
            ),
            (
                np.pi / 4,
                qml.Hamiltonian(
                    [1, 1, 1], [qml.PauliX(0), qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliX(1)]
                ),
                1,
                [0.0, 0.0],
            ),
            (
                1,
                qml.Hamiltonian([1, 1], [qml.PauliX(0), qml.PauliX(1)]),
                2,
                [-0.41614684, -0.41614684],
            ),
            (
                2,
                qml.Hamiltonian(
                    [1, 1, 1, 1],
                    [qml.PauliX(0), qml.PauliY(0), qml.PauliZ(0) @ qml.PauliZ(1), qml.PauliY(1)],
                ),
                2,
                [-0.87801124, 0.51725747],
            ),
        ],
    )
    def test_evolution_output(self, time, hamiltonian, steps, expectation):
        """Tests that the output from the ApproxTimeEvolution template is correct"""

        n_wires = 2
        dev = qml.device("default.qubit", wires=n_wires)

        @qml.qnode(dev)
        def circuit():
            qml.ApproxTimeEvolution(hamiltonian, time, steps)
            return [qml.expval(qml.PauliZ(wires=i)) for i in range(n_wires)]

        assert np.allclose(circuit(), expectation)

    def test_custom_wire_labels(self, tol):
        """Test that template can deal with non-numeric, nonconsecutive wire labels."""
        hamiltonian = qml.Hamiltonian([1, 1, 1], [qml.PauliX(0), qml.PauliX(1), qml.PauliX(2)])
        hamiltonian2 = qml.Hamiltonian(
            [1, 1, 1], [qml.PauliX("z"), qml.PauliX("a"), qml.PauliX("k")]
        )

        dev = qml.device("default.qubit", wires=3)
        dev2 = qml.device("default.qubit", wires=["z", "a", "k"])

        @qml.qnode(dev)
        def circuit():
            qml.ApproxTimeEvolution(hamiltonian, 0.5, 2)
            return qml.expval(qml.Identity(0))

        @qml.qnode(dev2)
        def circuit2():
            qml.ApproxTimeEvolution(hamiltonian2, 0.5, 2)
            return qml.expval(qml.Identity("z"))

        circuit()
        circuit2()

        assert np.allclose(dev.state, dev2.state, atol=tol, rtol=0)