def __init__(self, hamiltonian, time, frequencies=None, shifts=None, do_queue=True, id=None): from pennylane.gradients.general_shift_rules import ( get_shift_rule, ) # pylint: disable=import-outside-toplevel if not isinstance(hamiltonian, qml.Hamiltonian): raise TypeError( "hamiltonian must be of type pennylane.Hamiltonian, got {}".format( type(hamiltonian).__name__ ) ) trainable_hamiltonian = qml.math.requires_grad(hamiltonian.coeffs) if frequencies is not None and not trainable_hamiltonian: self.grad_recipe = (get_shift_rule(frequencies, shifts)[0],) + (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_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: get_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
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, 1.0, np.pi / 8], [0.31327576445128014, 1.0, 3 * np.pi / 8], [-0.8080445791083615, 1.0, 5 * np.pi / 8], [-0.3101398980494395, 1.0, 7 * np.pi / 8], [-2.8111804455102014, 1.0, -np.pi / 8], [-0.31327576445128014, 1.0, -3 * np.pi / 8], [0.8080445791083615, 1.0, -5 * np.pi / 8], [0.3101398980494395, 1.0, -7 * np.pi / 8], ] generated_terms = get_shift_rule(frequencies)[0] assert all([ all(np.isclose(generated_terms[i], correct_terms[i])) for i in range(n_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, 1, 0.7853981633974483], [-0.8720240894718643, 1, 1.0471975511965976], [0.016695190986336428, 1, 2.0943951023931953], [-1.7548361197453346, 1, -0.7853981633974483], [0.8720240894718643, 1, -1.0471975511965976], [-0.016695190986336428, 1, -2.0943951023931953], ] generated_terms = get_shift_rule(frequencies, custom_shifts)[0] assert all([ all(np.isclose(generated_terms[i], correct_terms[i])) for i in range(n_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, 1.0, np.pi / 13], [-0.12914139932030527, 1.0, 3 * np.pi / 7], [-0.3820906256032637, 1.0, 2 * np.pi / 3], [0.436088184940856, 1.0, 3 * np.pi / 4], [-2.709571194594805, 1.0, -np.pi / 13], [0.12914139932030527, 1.0, -3 * np.pi / 7], [0.3820906256032637, 1.0, -2 * np.pi / 3], [-0.436088184940856, 1.0, -3 * np.pi / 4], ] generated_terms = get_shift_rule(frequencies, custom_shifts)[0] assert all([ all(np.isclose(generated_terms[i], correct_terms[i])) for i in range(n_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, 1.0, np.pi / 2], [-0.5, 1.0, -np.pi / 2]] generated_terms = get_shift_rule(frequencies)[0] assert all([ all(np.isclose(generated_terms[i], correct_terms[i])) for i in range(n_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, 1, 3 * np.pi / 4], [-0.048815536468908745, 1, 9 * np.pi / 4], [-0.2845177968644246, 1, -3 * np.pi / 4], [0.048815536468908745, 1, -9 * np.pi / 4], ] generated_terms = get_shift_rule(frequencies)[0] assert all([ all(np.isclose(generated_terms[i], correct_terms[i])) for i in range(n_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, 1.0, np.pi / 4], [-0.14644660940672624, 1.0, 3 * np.pi / 4], [-0.8535533905932737, 1.0, -np.pi / 4], [0.14644660940672624, 1.0, -3 * np.pi / 4], ] generated_terms = get_shift_rule(frequencies)[0] assert all([ all(np.isclose(generated_terms[i], correct_terms[i])) for i in range(n_terms) ])