def test_second_order_two_term_shift_rule(self):
     """Test that the second order shift rule is correct and
     properly simplified"""
     frequencies = (1, )
     generated_terms = generate_shift_rule(frequencies, order=2)
     correct_terms = [[-0.5, 0], [0.5, -np.pi]]
     assert np.allclose(generated_terms.T, correct_terms)
    def test_near_singular_warning(self):
        """Tests a warning is raised if the determinant of the matrix to be inverted is near zero
        for obtaining parameter shift rules for the non-equidistant frequency case."""

        frequencies = (1, 2, 3, 4, 5, 67)

        with pytest.warns(None) as warnings:
            generate_shift_rule(frequencies)

        raised_warning = False
        for warning in warnings:
            if "Solving linear problem with near zero determinant" in str(
                    warning):
                raised_warning = True

        assert raised_warning
Example #3
0
    def __init__(self,
                 hamiltonian,
                 time,
                 frequencies=None,
                 shifts=None,
                 do_queue=True,
                 id=None):
        # pylint: disable=import-outside-toplevel
        from pennylane.gradients.general_shift_rules import (
            generate_shift_rule, )

        if not isinstance(hamiltonian, qml.Hamiltonian):
            type_name = type(hamiltonian).__name__
            raise TypeError(
                f"hamiltonian must be of type pennylane.Hamiltonian, got {type_name}"
            )

        trainable_hamiltonian = qml.math.requires_grad(hamiltonian.coeffs)
        if frequencies is not None and not trainable_hamiltonian:
            c, s = generate_shift_rule(frequencies, shifts)
            recipe = qml.math.stack([c, qml.math.ones_like(c), s]).T
            self.grad_recipe = (recipe, ) + (None, ) * len(hamiltonian.data)
            self.grad_method = "A"

        self.hamiltonian = hamiltonian
        self.num_params = len(hamiltonian.data) + 1
        self.frequencies = frequencies
        self.shifts = shifts

        super().__init__(time,
                         *hamiltonian.data,
                         wires=hamiltonian.wires,
                         do_queue=do_queue,
                         id=id)
 def test_second_order_two_term_shift_rule_custom_shifts(self):
     """Test that the second order shift rule is correct and
     properly simplified when custom shift values are provided"""
     frequencies = (1, )
     generated_terms = generate_shift_rule(frequencies,
                                           shifts=(np.pi / 4, ),
                                           order=2)
     correct_terms = [[-1, 0], [0.5, -np.pi / 2], [0.5, np.pi / 2]]
     assert np.allclose(generated_terms.T, correct_terms)
    def test_two_term_rule_default_shifts(self):
        """Tests the correct two term equidistant rule is generated using default shift pi/2.
        Frequency 1 corresponds to any generator of the form: 1/2*P, where P is a Pauli word."""

        frequencies = (1, )

        n_terms = 2
        correct_terms = [[0.5, -0.5], [np.pi / 2, -np.pi / 2]]
        generated_terms = generate_shift_rule(frequencies)

        assert np.allclose(generated_terms, correct_terms)
 def test_second_order_four_term_shift_rule(self):
     """Test that the second order shift rule is correct and
     properly simplified for generators with 4-term rules"""
     frequencies = (0.5, 1)
     generated_terms = generate_shift_rule(frequencies, order=2)
     correct_terms = [
         [-0.375, 0],
         [0.25, -np.pi],
         [0.25, np.pi],
         [-0.125, -2 * np.pi],
     ]
     assert np.allclose(generated_terms.T, correct_terms)
 def test_second_order_non_equidistant_shift_rule(self):
     """Test that the second order shift rule is correct and
     properly simplified for generators with non-equidistant frequencies"""
     frequencies = (2, 3)
     generated_terms = generate_shift_rule(frequencies, order=2)
     correct_terms = [
         [-6, 0],
         [3.91421356, -np.pi / 4],
         [3.91421356, np.pi / 4],
         [-1, -np.pi / 2],
         [-1, np.pi / 2],
         [0.08578644, -3 * np.pi / 4],
         [0.08578644, 3 * np.pi / 4],
     ]
     assert np.allclose(generated_terms.T, correct_terms)
    def test_non_integer_frequency_default_shifts(self):
        """Tests the correct four term shift rule is generated given non-integer frequencies."""

        frequencies = (1 / 3, 2 / 3)
        n_terms = 4

        correct_terms = [
            [0.2845177968644246, 3 * np.pi / 4],
            [-0.2845177968644246, -3 * np.pi / 4],
            [-0.048815536468908745, 9 * np.pi / 4],
            [0.048815536468908745, -9 * np.pi / 4],
        ]

        generated_terms = generate_shift_rule(frequencies)

        assert np.allclose(generated_terms.T, correct_terms)
    def test_four_term_rule_default_shifts(self):
        """Tests the correct two term equidistant rule is generated using the default shifts [pi/4, 3*pi/4].
        The frequency [1,2] corresponds to a generator e.g. of the form 1/2*X0Y1 + 1/2*Y0X1."""

        frequencies = (1, 2)

        n_terms = 4
        correct_terms = [
            [
                0.8535533905932737, -0.8535533905932737, -0.14644660940672624,
                0.14644660940672624
            ],
            [np.pi / 4, -np.pi / 4, 3 * np.pi / 4, -3 * np.pi / 4],
        ]
        generated_terms = generate_shift_rule(frequencies)

        assert np.allclose(generated_terms, correct_terms)
    def test_eight_term_rule_non_equidistant_default_shifts(self):
        """Tests the correct non-equidistant eight term shift rule is generated given the
        frequencies using the default shifts. The frequency [1,4,5,6] corresponds to e.g.
        a 2-qubit generator of the form: 1/2*X0Y1 + 5/2*Y0X1."""

        frequencies = (1, 4, 5, 6)

        n_terms = 8

        correct_terms = [
            [2.8111804455102014, np.pi / 8],
            [-2.8111804455102014, -np.pi / 8],
            [0.31327576445128014, 3 * np.pi / 8],
            [-0.31327576445128014, -3 * np.pi / 8],
            [-0.8080445791083615, 5 * np.pi / 8],
            [0.8080445791083615, -5 * np.pi / 8],
            [-0.3101398980494395, 7 * np.pi / 8],
            [0.3101398980494395, -7 * np.pi / 8],
        ]

        generated_terms = generate_shift_rule(frequencies)

        assert np.allclose(generated_terms.T, correct_terms)
    def test_non_integer_frequency_custom_shifts(self):
        """Tests the correct four term shift rule is generated given non-integer frequencies using
        explicitly defined shifts."""

        frequencies = (1 / 3, 2 / 3, 4 / 3)
        custom_shifts = (
            np.pi / 4,
            np.pi / 3,
            2 * np.pi / 3,
        )
        n_terms = 6

        correct_terms = [
            [1.7548361197453346, 0.7853981633974483],
            [-1.7548361197453346, -0.7853981633974483],
            [-0.8720240894718643, 1.0471975511965976],
            [0.8720240894718643, -1.0471975511965976],
            [0.016695190986336428, 2.0943951023931953],
            [-0.016695190986336428, -2.0943951023931953],
        ]

        generated_terms = generate_shift_rule(frequencies, custom_shifts)

        assert np.allclose(generated_terms.T, correct_terms)
    def test_eight_term_rule_non_equidistant_custom_shifts(self):
        """Tests the correct non-equidistant eight term shift rule is generated given the
        frequencies using non-default shifts. The frequency [1,4,5,6] corresponds to e.g.
        a 2-qubit generator of the form: 1/2*X0Y1 + 5/2*Y0X1."""

        frequencies = (1, 4, 5, 6)
        custom_shifts = (1 / 13 * np.pi, 3 / 7 * np.pi, 2 / 3 * np.pi,
                         3 / 4 * np.pi)

        n_terms = 8
        correct_terms = [
            [2.709571194594805, np.pi / 13],
            [-2.709571194594805, -np.pi / 13],
            [-0.12914139932030527, 3 * np.pi / 7],
            [0.12914139932030527, -3 * np.pi / 7],
            [-0.3820906256032637, 2 * np.pi / 3],
            [0.3820906256032637, -2 * np.pi / 3],
            [0.436088184940856, 3 * np.pi / 4],
            [-0.436088184940856, -3 * np.pi / 4],
        ]

        generated_terms = generate_shift_rule(frequencies, custom_shifts)

        assert np.allclose(generated_terms.T, correct_terms)